RASA form validation - Rasa Open Source - Rasa Community Forum
👋 Introducing the Rasa Playground
RASA form validation
post by indranil180 on Jul 23, 2019
I have created a form in rasa in which i want to validate the slots for that i want to create generic validate method which can handle any number of slots. I have the slot details in an excel sheet. I am picking the slot names from there but i don’t know how to keep track of which slots are filled and which are not and how to ask for the next slot… Can anyone please help me.
post by tyd on Jul 23, 2019
Hi @indranil180! Can you show me what your stories look like? Are you trying to create a form with a dynamic number of slots?
post by indranil180 on Jul 23, 2019
yes i am looking to create a form with dynamic number of slots.
post by tyd on Jul 23, 2019
@indranil180 What do your stories look like? Can you tell me more about why you want to do this?
post by indranil180 on Jul 23, 2019
Stories.md
## story 01
* greet
- utter_greet
## story 02
* goodbye
- utter_goodbye
## story 03
* intent_add
- action_static
## happy path
* greet
- utter_greet
* request_restaurant
- dynamic_form
- form{"name": "dynamic_form"}
- form{"name": null}
- utter_slots_values
This is how my stories look. We want our bot to be ready to use so rather than coding for specific purpose we want it to handle dynamic slots. Maybe in some scenario slots are more than one in some scenarios we have just one slot. So to handle that thing we want to create a generic Form class which can handle everything.
post by fede on Jul 23, 2019
Hey @indranil180, in order to create a form with a custom set of slots, your domain file needs to list each of those slots, and also contain a utter_ask_{slot} action for each slot. These elements cannot be set up after training your model, so they will need to be in your domain file before you train it. The closest you can get to a form with dynamic list of slots is, for the moment, to generate your domain file using a script, and then training the model. If the slot list changes, you will need to re-generate the domain and re-train your model.
If your Excel file only changes every now and then, this could be a viable solution to your problem.
post by indranil180 on Jul 24, 2019
I have written code which set these elements up before training model. The challenge i am facing is while validating the dynamic slots. Can you help me in the validation step. Plus i have one more question do i need template for form or i can send those validation messages through utter_message rather than using utter_template.
post by nikhilcss97 on Jul 24, 2019
Hey @indranil180, you can have a generic validate() method in your custom FormAction where you can take in the slot values and validate the same.
For your second question, you can have an utter_message instead of an utter_template to send messages. Both will work fine.
post by indranil180 on Jul 24, 2019
Thanks for your response. I am following below code to achieve generic validation.
class insuranceform(FormAction):
def name(self):
return 'insurance_form'
@staticmethod
def required_slots(tracker):
return ["firstname","lastname","gender","dob","email","contact","address","city","state","zipcode","ssn"]
def validate(self, dispatcher, tracker, domain):
slot_values = self.extract_other_slots(dispatcher, tracker, domain)
slot_to_fill = tracker.get_slot(REQUESTED_SLOT)
if slot_to_fill:
slot_values.update(self.extract_requested_slot(dispatcher, tracker, domain))
#response1 = "HELLOHELLO "
#dispatcher.utter_message(response1)
for slot, value in slot_values.items():
#dispatcher.utter_message("line3")
if slot == 'firstname':
if value.replace(" ","").isalpha() == False:
dispatcher.utter_template('utter_wrong_firstname', tracker)
slot_values[slot] = None
else:
dispatcher.utter_message("Hi {}".format(value))
elif slot == 'lastname':
if value.replace(" ","").isalpha() == False:
dispatcher.utter_template('utter_wrong_lastname', tracker)
slot_values[slot] = None
elif slot == 'gender':
if value.lower() not in ["male","female"]:
dispatcher.utter_template('utter_wrong_gender', tracker)
slot_values[slot] = None
elif slot == 'dob':
try:
datetime.strptime(value, '%d-%m-%Y')
except ValueError:
dispatcher.utter_template('utter_wrong_dob', tracker)
slot_values[slot] = None
elif slot == 'email':
email = re.compile(r'(^[a-zA-Z0-9_.+-]+@[a-zA-Z0-9-]+
.[a-zA-Z0-9-.]+$)')
mo = email.search(value)
if mo == None:
dispatcher.utter_template('utter_wrong_email', tracker)
slot_values[slot] = None
elif slot == 'contact':
if len(value) != 10 or value.isdigit() == False:
dispatcher.utter_template('utter_wrong_contact', tracker)
slot_values[slot] = None
elif slot == 'city':
if value.replace(" ","").isalpha() == False:
dispatcher.utter_template('utter_wrong_city', tracker)
slot_values[slot] = None
elif slot == 'state':
if value.replace(" ","").isalpha() == False:
dispatcher.utter_template('utter_wrong_state', tracker)
slot_values[slot] = None
elif slot == 'zipcode':
if len(value) != 5 or value.isdigit() == False:
dispatcher.utter_template('utter_wrong_zipcode', tracker)
slot_values[slot] = None
elif slot == 'ssn':
ssn = re.compile(r'^
{3}-
{2}-
{4}$')
mo = ssn.search(value)
if mo == None:
dispatcher.utter_template('utter_wrong_ssn', tracker)
slot_values[slot] = None
return [SlotSet(slot, value) for slot, value in slot_values.items()]
def submit(self, dispatcher, tracker, domain):
#response1 = "HELLOHELLOaa "
#dispatcher.utter_message(response1)
firstname=tracker.get_slot("firstname")
lastname=tracker.get_slot("lastname")
gender=tracker.get_slot("gender")
dob=tracker.get_slot("dob")
email=tracker.get_slot("email")
contact=tracker.get_slot("contact")
address=tracker.get_slot("address")
city=tracker.get_slot("city")
state=tracker.get_slot("state")
zipcode=tracker.get_slot("zipcode")
ssn=tracker.get_slot("ssn")
SlotSet('zipcode', None)
SlotSet('zipcode', "11111")
dispatcher.utter_message("Here is the details you have entered.Please review")
dispatcher.utter_message('''First Name : {}
Last Name : {}
Gender : {}
DOB : {}
Email : {}
Contact : {}
Address : {}
City : {}
state : {}
Zip code : {}
SSN : {}'''.format(firstname,lastname,gender,dob,email,contact,address,city,state,zipcode,ssn))
dispatcher.utter_button_message("Do you want to change any field", [{"title": "Yes", "payload": "/affirm"},{"title": "No", "payload": "/deny"}])
return []
I don’t know how i can pass the dynamic slot name in if condition if slot == 'firstname': I know it sounds noob but i don’t know how to do that. Please help.
post by fede on Jul 24, 2019
Sorry, I’m not sure I understand the question: as you iterate through each element of slot_values.items(), shouldn’t the variable slot take the value of each slot name?
post by indranil180 on Jul 25, 2019
i solved that issue. Thanks for the help. I have just one question. Every time the form gets called it will ask for the required slots. I have not created any templates to i didn’t got the ask question. I tried to specify the question from utter_message but it seems it is not working. So will it only work with a template or i can do some work around with utter_message?
post by fede on Jul 25, 2019
For every slot defined, you should define a utter_ask_{slot} action as well. This action will be used to ask the user for the value of its slot. For example:
templates:
utter_ask_cuisine:
- text: "what cuisine?"
utter_ask_num_people:
- text: "how many people?"
utter_ask_outdoor_seating:
- text: "do you want to seat outside?"
This blog post gives some great examples of how to use forms and slots. Hope it’s useful!
post by indranil180 on Jul 25, 2019
can’t i make these template as generic so that i can call them from my validate method.
Expectation:
templates:
utter_ask_{slots}:
- text: what is {slots}
And from the code i can call dispatcher.utter_message("utter_ask_{}".format(slot),tracker)
is this possible ?
post by fede on Jul 25, 2019
I don’t think that’s possible, sorry. You’ll need to have a utter_ask_{slot} on your domain file for each slot before you train your model.
post by indranil180 on Jul 25, 2019
Thanks actually i am struggling quite a lot because we want to make the chatbot to handle dynamic data.thats why i want this approach. I am using tracker.get_slot(REQUESTED_SLOT) and self.extract_other_slots(dispatcher, tracker, domain) to do some work around but it turns out the values are empty during the first time form is called. Once i enter something in input then only these values are getting updated. So i am looking for some alternative.
post by Meghnahh on Sep 24, 2020
Hi, can you please help me make this validation dynamic? I’m facing issues. particularly, in running the action file I’m facing an indentation error. I have created slots in the domain file and my action file has a code similar to yours
class InsuranceForm(FormAction):
def name(self):
return "insurance_form"
def required_slots(self,tracker) -> List[Text]:
return ["name","email","dateofbirth","number","address","zip"]
def slot_mappings(self) -> Dict[Text, Union[Dict, List[Dict]]]:
return {
"name": [
self.from_text(),
],
"email": [
self.from_text(),
],
"dateofbirth": [
self.from_text(),
],
"number": [
self.from_text(),
],
"address": [
self.from_text(),
],
"zip": [
self.from_text(),
],
}
def validate(self, dispatcher, tracker, domain):
slot_values = self.extract_other_slots(dispatcher, tracker, domain)
slot_to_fill = tracker.get_slot(REQUESTED_SLOT)
if slot_to_fill:
slot_values.update(self.extract_requested_slot(dispatcher, tracker, domain))
for slot, value in slot_values.items():
if slot == 'name':
if value.replace(" ","").isalpha() == False:
dispatcher.utter_template('utter_wrong_name', tracker)
slot_values[slot] = None
else:
dispatcher.utter_message("Hi {}".format(value))
elif slot == 'address':
if value.replace(" ","").isalpha() == False:
dispatcher.utter_template('utter_wrong_address', tracker)
slot_values[slot] = None
elif slot == 'dateofbirth':
try:
datetime.strptime(value, '%d-%m-%Y')
except ValueError:
dispatcher.utter_template('utter_wrong_dob', tracker)
slot_values[slot] = None
elif slot == 'email':
email = re.compile(r'(^[a-zA-Z0-9_.+-]+@[a-zA-Z0-9-]+
.[a-zA-Z0-9-.]+$)')
mo = email.search(value)
if mo == None:
dispatcher.utter_template('utter_wrong_email', tracker)
slot_values[slot] = None
elif slot == 'number':
if len(value) != 10 or value.isdigit() == False:
dispatcher.utter_template('utter_wrong_contact', tracker)
slot_values[slot] = None
elif slot == 'zip':
if len(value) != 5 or value.isdigit() == False:
dispatcher.utter_template('utter_wrong_zipcode', tracker)
slot_values[slot] = None
return [SlotSet(slot, value) for slot, value in slot_values.items()]
post by indranil180 on Sep 24, 2020
Can you please be more specific about the error. Can you share the logs ?
post by Meghnahh on Sep 24, 2020
My stories file is this
happy path
- greet
- utter_greet
insurance path
insurance_form
form{“name”:“insurance_form”}
form{“name”:“null”}
say personal
insurance
- insurance_form
form{“name”:“insurance_form”}
form{“name”:“null”}
utter_insurance
insurance path 1
greet
- utter_greet
insurance
insurance_form
form{“name”:“insurance_form”}
form{“name”:“null”}
affirm
- utter_happy
And the error I’m getting when I run actions server is this:
TabError: inconsistent use of tabs and spaces in indentation
post by Meghnahh on Sep 24, 2020
domain.yml:
session_config:
session_expiration_time: 60
carry_over_slots_to_new_session: true
intents:
greet
goodbye
affirm
deny
mood_great
mood_unhappy
bot_challenge
insurance
slots:
address:
auto_fill: false
type: unfeaturized
email:
auto_fill: false
type: unfeaturized
name:
auto_fill: false
type: unfeaturized
stories:
responses:
utter_ask_address:
- text: "Enter your address?"
utter_ask_email:
- text: "Enter your Email?"
utter_ask_name:
- text: "Enter your name?"
utter_ask_dateofbirth:
- text: "Enter your date of birth"
utter_ask_number:
- text: "Enter your Number?"
utter_ask_zip:
- text: "Enter your zip code?"
utter_greet:
- text: Hi, thanks for reaching out to us at ABC Insurance Company. What type of insurance are you looking for today?
utter_cheer_up:
text: ‘Here is something to cheer you up:’
utter_did_that_help:
- text: Did that help you?
utter_happy:
- text: Great, carry on!
utter_goodbye:
- text: Bye
utter_iamabot:
- text: I am a bot, powered by Rasa.
utter_insurance:
- text: Help us get you free quotes from top insurers with the lowest premiums.
utter_wrong_name:
- text: The name you entered is not alphabetical. Please enter a valid name.
utter_wrong_email:
- text: The email you entered is invalid. Please enter a valid email.
utter_wrong_dob:
- text: The date of birth is invalid. Please enter a valid date of birth.
utter_wrong_zipcode:
- text: Wrong zip code. Please enter a valid zipcode
utter_wrong_contact:
- text: Wrong contact number. Please enter a valid number
actions:
utter_greet
utter_goodbye
utter_iamabot
utter_insurance
forms:
- insurance_form