Hello, I have two different forms that requires the user to input a number. Depending of the first input, a different second form is activated. Both the forms require just a float number. The problem is that, as soon as the second form is activated, the action_extract_slots is automatically executed, and the required slot is automatically filled with the answer the user provided in the previous form. It seems to be impossible to wait for the user answer, as no action_listen is activated. Do you know how to avoid this behaviour and force Rasa to wait for the user input after the form activation?
Are you using two separate slots for the numbers? Are you using duckling for the number extraction?
If you’re using separate slots then this shouldn’t be an issue.
Yes, I am using two separate slots. They are defined as follows:
activity_useful_rating:
type: float
influence_conversation: false
mappings:
- type: from_text
conditions:
- active_loop: activity_usefulness_form
save_or_edit_slot:
type: float
influence_conversation: true
mappings:
- type: from_text
conditions:
- active_loop: save_or_edit_form
And the forms are defined in this way:
activity_usefulness_form:
required_slots:
- activity_useful_rating
save_or_edit_form:
required_slots:
- save_or_edit_slot
From the debug I see this when save_or_edit_form form is activated (6 is the answer to the activity_usefulness_form form):
2022-10-21 15:46:59 DEBUG rasa.core.actions.forms - Activated the form 'save_or_edit_form'.
2022-10-21 15:46:59 DEBUG rasa.core.actions.forms - Executing default action 'action_extract_slots' at form activation.
2022-10-21 15:46:59 DEBUG rasa.core.actions.action - Validating extracted slots: save_or_edit_slot
2022-10-21 15:46:59 DEBUG rasa.core.actions.forms - The execution of 'action_extract_slots' resulted in these events: SlotSet(key: save_or_edit_slot, value: 6).
2022-10-21 15:46:59 DEBUG rasa.core.actions.forms - Validating pre-filled required slots: {'save_or_edit_slot': '6'}
2022-10-21 15:46:59 DEBUG rasa.core.actions.forms - Validating extracted slots: {'save_or_edit_slot': '6'}
2022-10-21 15:46:59 DEBUG rasa.core.actions.action - Calling action endpoint to run action 'validate_save_or_edit_form'
For the number extraction I am not using duckling.
Use should use duckling in this case. Take a look at this blog post on entity extraction. Even if you choose not to use duckling, you should define an entity for your numbers and use from_entity
to map the entity to your slots:
activity_useful_rating:
type: any
influence_conversation: false
mappings:
- type: from_entity
entity: NUMBER
influence_conversation
should be set to false
for save_or_edit_slot
.
The type
setting of float
isn’t adding any value here so I would change that to any
or text
.
Thank you for the suggestion! I tried this approach, but the issue persists. Now the entity is extracted from the answer to activity_useful_rating
and it is used to validate the input of save_or_edit_form
form. The expected input is the same (in both the forms the user writes just a number), so I cannot define different intents either.
More in general, this same issue is consistent in other scenarios. For example, we want the user to input some free text in a form and verify only the text length. We cannot use entities, as the input is completely free, and we don’t take decisions on that. In this case again at the form activation the slot is automatically extracted from the previous user input and validated.
I found a functional solution to this problem, even if it is not so clean.
It is possible to use the validation actions to distinguish whether the form has been presented to the user or not, by looking at the utter_action
performed by the bot. If the last utterance is not the form activation utterance, than the slot can be set to None
and the form will be shown:
class ValidateSaveOrEditForm(FormValidationAction):
def name(self) -> Text:
return 'validate_save_or_edit_form'
def validate_save_or_edit_slot(
self, value: Text, dispatcher: CollectingDispatcher,
tracker: Tracker, domain: Dict[Text, Any]) -> Dict[Text, Any]:
events_bot = []
for event in events:
if event['event'] == 'bot':
events_bot.append(event)
last_utterance = events_bot[-1]['metadata']['utter_action']
if last_utterance != 'utter_ask_save_or_edit_slot':
return {"save_or_edit_slot": None}
else:
return {"save_or_edit_slot": value}
I am still wondering whether Rasa provides a more consistent solution to this, as it is a very strange behaviour that was not present in older versions.