Can't handle the complex story flow

Hello All,

Help me please, I am trying to handle the complex story and always fail. The story is about the tasks that user can solve by typing in chat.

Example: User needs to answer several questions, but the thing is that there is no predefined answer, so I can’t use the specific intent. I want to collect user’s answers from inputs whatever they can be.

  • 1 - quesiton
  • answer (any user input)
  • answer (any user input)
  • Done - if user types done, then bot can switch to another one
  • 2 - question
  • answer (any user input)
  • Done
  • Take user inputs and concat as one and save(this I can do by go through all previous events and extract all user messages)

How to make the story and accept any input and to make predictions?

My story looks like this right now:

  • bd93f38c{“task_id”:“713”}
    • utter_we_are_aiming_to
    • utter_we_are_working_in_agile
    • utter_ask_user_about_agile
  • done
    • utter_ask_user_worked_in_agile
  • affirm
    • utter_ask_user_worked_in_agile_details
  • done
    • utter_refresh_agile_knowledge_message
    • utter_agile_task_links
    • action_post_multi_answers_task
    • slot{“task_id”:null}
    • slot{“fallback_count”:null}

I can share the task itself:

Help please.

You can try using FormAction and see if it will help with your situation: Forms. With FormAction, you can use custom slots mapping to make the bot store user’s answer (whatever it is) in a slot. You can also validate user’s input and if it’s ‘Done’, deactivate the FormAction.

1 Like

@fuih I was thinking about this, but how to manage any user input, any numbers of it and not to predict it until done? Can you please share some thoughts? Any example?

I’m not sure i fully understand your idea, but if you want to take user input as a whole text and don’t care about what intent it is then you can use the custom slots mapping function self.from_text():

def slot_mappings(self) -> Dict[Text, Union[Dict, List[Dict]]]:
    """A dictionary to map required slots to
        - an extracted entity
        - intent: value pairs
        - a whole message
        or a list of them, where a first match will be picked"""

    return {
        "answer_1": self.from_text(),
        "answer_2": self.from_text()

When asking for 2 slots ‘answer_1’ and ‘answer_2’, the bot will take whatever the text which the user enter and store in those slots, regardless of the intents. But keep in mind if the user enters something that matches an intent which has an action or a FormAction mapped to it, those actions still gonna get executed (i think).

1 Like

Thanks for sharing. Will self.from_text() take any number on user inputs, I mean can user type 3 messages in the row and will it map in that “answer_1”? In validation if it will be “Done” I just need to return the “answer_1” and it will go to the second one automatically ? Or do I need to trigger somehow and “say to rasa that this is filled, go and ask another question”?

No, it only takes the first message that the user enters.

In validation, if you want to get out of the form, simply return self.deactivate(). If you want the form to keep working (asking for answer 2) then just return an empty list [] in the validate_{slot_name} function. You can also make the bot ask users again if you don’t like the user’s answer (by setting the slot to None with SlotSet(slot_name, None)).

@fuih Thank you. Do you know how can I get few user answers. Like:

  • question
  • user answer (bot doesn’t do anything)
  • user answer (bot doesn’t do anything)
  • and so on, until he will type Done

In the validation?

I can think of a way, although i don’t know if it’s a good practice or not.

So you can create a story like this:

## example
* user's intent
    - utter_question
    - get_answer_form
    - form{"name": "get_answer_form"}
    - form{"name": null}

The get_answer_form will has 1 requested_slot ‘answer’.

Then you don’t define any utter for that slot, which means the bot will not ask the user anything, but still expected the user to provide information for that slot.

You use self.from_text() for the slot to receive any text which the user enters.

Then in validate function, you check if it’s not ‘Done’, you take the text and save it from somewhere (i don’t know maybe create another slot for it ?), then set the slot ‘answer’ to None with SlotSet(slot_name, None). Because of this, the bot will attempt to ask the user again for the slot (but there is no defined utter for it so it will not output anything and keep waiting for the slot ‘answer’ again). Repeat the process, keep taking the texts and save them somewhere.

If the user enters ‘Done’, simply let’s the FormAction close itself. You can leave the submit function empty for this or use self.deactivate().

1 Like

not to define utter_ for slot, hmm, can work. I will try.

Thank you very much.