# Custom Forms

# Introduction

Let's have a quick look at your project folder structure:

awesome-project
|- .botfront
|- actions
|- botfront-db
|- models
Folder Description
.botfront Project configuration files, docker-compose files
actions Custom actions for the actions server
botfront-db MongoDB persisted files
models Persisted models

You probably figured it out: actions is our folder of interest.

TLDR;

If you already know about Rasa and custom actions:

  • Add your actions in the actions/my_actions.py file.
  • Run botfront watch from the root of your project folder to automatically rebuild your action server on file changes.

# Tutorial

Let's build a conversation like this:

- User: i want to book a room 
- Bot: ok what is your name for booking 

But let's start with a simpler version:

- User: i want to book a room
- Bot: Ok

While taking baby steps...

# 1. Add a story

In a new story group, add the following story and click Train everything




* inform_guests
  - utter_ok

You can verify that the story works by typing /inform_guests in the chat window

TIP

Note that we prefixed the intent with /. Since there is no training data for that intent, we can't use natural language yet. The / allows us to invoke the intent directly.

The bot should reply with utter_ok.

# 2. Add training data to inform_guests

Add the following examples to the inform_guests intent of your NLU model and re-train it:

i want to book a room
i want room tonight 
booking room 

Add more intents

You need at least two different intents to train an NLU model. You can add more intents by importing from the Chit Chat tab.

# 3. Add a bot response

Finally, let's create a bot response for the utter_ok template we just put in the story:

TIP

You just created a sequence of messages. The bot will utter 2 messages even if your story only had one action following * inform_guests

Let's just remind ourselves of our end goal:

- User: i want to book a room 
- Bot: ok what is your name for booking

- so let's Creat form action to ask user to enter his name (in this EX but we can add form action to fill any other data(phone,date,company_name... ))

# 6. Create a form action

Open the actions folder and add a new file called my_actions.py and paste the following content:

import logging
from functools import reduce
from typing import Dict, Text, Any, List, Union
from rasa_sdk import ActionExecutionRejection
from rasa_sdk import Tracker
from rasa_sdk.events import SlotSet, AllSlotsReset
from rasa_sdk.executor import CollectingDispatcher
from rasa_sdk.forms import FormAction, REQUESTED_SLOT

logging.basicConfig(level="DEBUG")
logger = logging.getLogger()

class Name_Form(FormAction):
	"""Example of a custom form action"""

	def name(self):
		# type: () -> Text
		"""Unique identifier of the form"""

		return "name_form"

	@staticmethod
	def required_slots(tracker:Tracker) -> List[Text]:
		"""A list of required slots that the form has to fill"""

		return ["name"]

	def slot_mappings(self):
		# type: () -> 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 {"name": [self.from_entity(entity="name"),
							 self.from_text()]}
							   

	def submit(self,
			   dispatcher: CollectingDispatcher,
			   tracker: Tracker,
			   domain: Dict[Text, Any]) -> List[Dict]:
		"""Define what the form has to do
			after all required slots are filled"""
			
		"" here we can write code to do what we want (like if want to enter email here can check its format with specific structre (
			
			def validate_email(self,
							value: Text,
							dispatcher: CollectingDispatcher,
							tracker: Tracker,
							domain: Dict[Text, Any]) -> Any:
							
				regex = '^\w+([\.-]?\w+)*@\w+([\.-]?\w+)*(\.\w{2,3})+$'
				
				if(re.search(regex,value)):
					return value
				else:
					dispatcher.utter_template('utter_wrong_email', tracker)
					# validation failed, set slot to None
					return None
		
		)

		
		return []
		

Save your file. The actions service should be rebuilding and you should see this in the terminal window showing logs (botfront logs):

INFO:rasa_sdk.executor:Registered function for 'action_guests'.

# 7. Update your story

Now let's change the story we created earlier: replace the bot response utter_ok with name_form


 





* inform_guests
  - name_form 
  - form {"name":"name_form"} ## to deactivate the form after setting slot 
  - form {"name": null}
  - slot{"name": "any value"}

::: tips

  1. The action name name_form comes from the name() method of the GuestsAction class.

  2. In name_form, form muts be small not(capital)

  3. Slot name in story is the same name in your form action

  4. Must mention your slot in story sloyts to fill it

  5. Form action it return utterance what is value=(your slot name)

  6. Added you utterance to your responses

  7. When wanting to mention your slot in action out the form_action , must use (tracker.get_slot("your slot name"))

:::

# 8. Retrain and test your bot

Then you can see the result:

# 9. Shutting down

You can safely shut down your project with botfront down to free all resources. Your data is kept in the botfront-db folder and will be accessible from Botfront the next time you turn it on.

# Next steps

Congratulations, you've learned how to use Rasa with Botfront! Everything you see on official Rasa documentation should apply with a few exceptions such as voice and messaging platforms.