Rasa forms: how to get answer validation?

I have multiple questions with three choices. I use forms to go through questions. Then bot needs to send reply was the answer right or wrong, but so far not successful.

I’m using

Rasa 1.10.8

I have tried this


    @staticmethod
    def required_slots(tracker):

        return ["kysymys01", "kysymys02", "kysymys03", "kysymys04", "kysymys05", "kysymys06", "kysymys07", "kysymys08", "kysymys09", "kysymys10", "kysymys11", "kysymys12", "kysymys13", "kysymys14", "kysy$

    def slot_mappings(self, dispatcher: CollectingDispatcher) -> Dict[Text, Union[Dict, List[Dict]]]:
        return {
           "kysymys01": [
                self.from_intent(intent="oikea_vastaus",  value=True),
                self.from_intent(intent="vaara_vastaus",  value=False),
                if tracker.get_slot("kysymys01") == "vaara_vastaus":
                        dispatcher.utter_message("answer is wrong")
                if tracker.get_slot("kysymys01") == "oikea_vastaus":
                        dispatcher.utter_message("answer is right")

and this


def validate_answer(
    self,
    dispatcher: CollectingDispatcher,
    tracker: Tracker,
    domain: Dict[Text, Any], 
	) -> List[Dict]:

        if tracker.get_slot("kysymys01") == "vaara_vastaus":
           dispatcher.utter_message("answer is wrong")
		if tracker.get_slot("kysymys01") == "oikea_vastaus":
            dispatcher.utter_message("answer is right")

But no success. What to try next?

Hello @InnoOmnia

Am I understanding this correctly that you want your assistant to ask the user one question where the user has to choose between three options, and then repeat this process (with different questions and options)?

The most robust way here would be to use buttons, see Responses. If you want the user to respond with free form text, then you must make sure you have enough NLU training data and configured the DIETClassifier (if you use that) with sufficient training epochs (sometimes you might need 1000).

Yes, here are first three questions
(kysymys = question, vaara_vastaus=wrong_answer, oikea_vastaus=right_answer)

responses:
utter_ask_kysymys01:

  • text: “Question 1/20 The water pump raises 50 liters of water per minute. How long does it take to fill a 10,000 liter tank?”
    buttons:
    • title: “20 min”
      payload: “/vaara_vastaus”
    • title: “2 h”
      payload: “/vaara_vastaus”
    • title: “3 h 20 min”
      payload: “oikea_vastaus”

utter_ask_kysymys02:

  • text: “Question 2/20 Which of the following numbers is different from the others?”
    buttons:
    • title: “0,285”
      payload: “/vaara_vastaus”
    • title: “285/100”
      payload: “/oikea_vastaus”
    • title: “28,5%”
      payload: “/vaara_vastaus”

utter_ask_kysymys03:

  • text: “Question 3/20 Which statements is true?”
    buttons:
    • title: "250 ml = 0,25 dl "
      payload: “/vaara_vastaus”
    • title: "250 ml = 25 cl "
      payload: “/oikea_vastaus”
    • title: “250 ml = 2,5 l”
      payload: “/vaara_vastaus”

I looked this in your link, but I don’t know how repeat this with all questions and also if-then function is needed

actions.py
from rasa_sdk.interfaces import Action

class ActionGreet(Action):
def name(self):
return ‘action_greet’

def run(self, dispatcher, tracker, domain):
    dispatcher.utter_message(template="utter_greet")
    return []

You could use a form, as before, where three slots kysymys01, kysymys02, and kysymys02 are filled by intent, and the validation function checks the answer.

The code you provided in your original question doesn’t seem right. The if statement cannot be after "kysymys01": [.... Also note that the signature of your validation function is wrong. It should contain a value argument, as shown here.

In Rasa 2.0 you can define rules that loop through your questions based on a slot feature. With this you could in principle separate your question/answer list from the rest of the bot. There’d just be a slot that contains the current question and a slot that contains the number of the correct answer, and an action that asks the current question and some custom action that fills those two slots with new values based on some dataset.

Hi and thank you, can you elaborate more how to do this? I have been googling and reading multiple instructions about forms and custom actions, but still can’t understand how to do it.

Where exactly do you get stuck?

I’m using forms, so now chatbot goes though 20 question which all have three possible answers as buttons and where is one right answer.

I have done earlier a form based chatbot which ask 22 questions with 2 possible answers and store them to slots and after all questions has been answered, print out those were answer was wrong.

So that chatbot prints out verdict AFTER ALL questions has been answered. Now I need to make bot which analyses user choice and then replies if that choice is right or wrong AFTER EACH question’s answer has been submitted

To check whether the user’s answer is correct after each step, and inform the user about it, I would use a validation function that sends the result to the user via dispatcher.utter_message(text=...).

Thanks for your fast reply, I have already tried that validation function but I can’t get it working. Here it is

   def validate_answer(  
        self,  
        value: Text,  
        dispatcher: CollectingDispatcher,  
        tracker: Tracker,  
        domain: Dict[Text, Any],
    ) -> Dict[Text, Any]:
        """Validate question answer."""
		
	if tracker.get_slot("kysymys01") == "True":
           dispatcher.utter_message("answer is Right")
		   return[]
		else:
			Dispatcher.utter_message("answer is wrong)
			return[]

I think it should be if tracker.get_slot("kysymys01") == True or just if tracker.get_slot("kysymys01"). Also, dispatcher is all lower case. And make sure the action server is running. If not, what error do you get?

P.S.: To post code blocks, please write three back-ticks ("```") before and after.

You also missed a / in the payload for question 1. I was going to say the same things at @j.mosig - True with no caps.

If that still doesn’t work, try changing your payload for each question like this -

utter_ask_kysymys01:

    text: Question 1/20 The water pump raises 50 liters of water per minute. How long does it take to fill a 10,000 liter tank?
    buttons:
        title: 20 min
        payload: '/vaara_vastaus{"kysymys01": False}'
        title: 2 h
        payload: '/vaara_vastaus{"kysymys01": False}'
        title: 3 h 20 min
        payload: '/oikea_vastaus{"kysymys01": True}'

and change them up for for each question.

Then the actual slot kysymys01 is then getting set when you click an answer In this case the intent

1 Like

Hi,
I got it working, not by using slots at all, just using stories to to show right response (correct/wrong) and then moving to next question.

Anyway I will also try to get this working with slots using your suggestions

Thanx
-pauli

2 Likes

That’s great!