I have created a form-action by following steps from the formbot and the form-action tutorial in the docs.
RASA core v-0.12.3
I have a story like this -
Story 1
Get_Restaurant
action_get_Restaurant
Affirm
action_affirm
consent_form
form{“name”: “consent_form”}
I have registered my form in forms tag in domain file.
On running my bot i am getting below line as a error
Exception: No registered Action found for name ‘consent_form’.
My form policy code looks like this -
class ConsentForm(FormAction):
“”“Example of a custom form action”“”
def name(self):
# type: () -> Text
"""Unique identifier of the form"""
return "consent_form"
@staticmethod
def required_slots(tracker: Tracker) -> List[Text]:
"""A list of required slots that the form has to fill"""
return ["consent"]
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 {
"consent": [self.from_entity(entity="user_consent"),
self.from_intent(intent='Affirm',
value=True),
self.from_intent(intent='Deny',
value=False)],
}
@staticmethod
def is_int(string: Text) -> bool:
"""Check if a string is an integer"""
try:
int(string)
return True
except ValueError:
return False
def validate(self,
dispatcher: CollectingDispatcher,
tracker: Tracker,
domain: Dict[Text, Any]) -> List[Dict]:
"""Validate extracted requested slot
else reject the execution of the form action
"""
# extract other slots that were not requested
# but set by corresponding entity
slot_values = self.extract_other_slots(dispatcher, tracker, domain)
# extract requested slot
slot_to_fill = tracker.get_slot(REQUESTED_SLOT)
if slot_to_fill:
slot_values.update(self.extract_requested_slot(dispatcher,
tracker, domain))
if not slot_values:
# reject form action execution
# if some slot was requested but nothing was extracted
# it will allow other policies to predict another action
raise ActionExecutionRejection(self.name(),
"Failed to validate slot {0} "
"with action {1}"
"".format(slot_to_fill,
self.name()))
# we'll check when validation failed in order
# to add appropriate utterances
for slot, value in slot_values.items():
if slot == 'consent':
if isinstance(value, str):
if 'yes' in value:
# convert "out..." to True
slot_values[slot] = True
elif 'no' in value:
# convert "in..." to False
slot_values[slot] = False
else:
dispatcher.utter_template('Please input with yes or no to move ahead',
tracker)
# validation failed, set slot to None
slot_values[slot] = None
# validation succeed, set the slots values to the extracted values
return [SlotSet(slot, value) for slot, value in slot_values.items()]
NotImplementedError: A form must implement required slots that it has to fill
127.0.0.1 - - [2019-01-18 11:57:21] "POST /webhook HTTP/1.1" 500 412 0.010005
2019-01-18 11:57:21 ERROR rasa_core.actions.action - Failed to run custom action 'count_episode'. Action server responded with a non 200 status code of 500. Make sure your action server properly runs actions and returns a 200 once the action is executed. Error: 500 Server Error: INTERNAL SERVER ERROR for url: http://localhost:5055/webhook
2019-01-18 11:57:21 ERROR rasa_core.processor - Encountered an exception while running action 'count_episode'. Bot will continue, but the actions events are lost. Make sure to fix the exception in your custom code.
2019-01-18 11:57:21 DEBUG rasa_core.processor - Failed to execute custom action.
Traceback (most recent call last):
File "/Users/anaconda3/lib/python3.6/site-packages/rasa_core/actions/action.py", line 339, in run
response.raise_for_status()
File "/Users/anaconda3/lib/python3.6/site-packages/requests/models.py", line 940, in raise_for_status
raise HTTPError(http_error_msg, response=self)
requests.exceptions.HTTPError: 500 Server Error: INTERNAL SERVER ERROR for url: http://localhost:5055/webhook
If I remember correctly, you need to restart the action server for the changes to take effect. Mine was running and not restarting because it didn’t shut down properly I think.
from rasa_core_sdk import Action
from rasa_core_sdk.events import SlotSet
from typing import Dict, Text, Any, List, Union, Optional
from rasa_core_sdk import ActionExecutionRejection
from rasa_core_sdk import Tracker
from rasa_core_sdk.executor import CollectingDispatcher
from rasa_core_sdk.forms import FormAction, REQUESTED_SLOT
#q = “select * from restaurants where cuisine=’{0}’ limit 1”.format(cuisine)
#result = db.query(q)
result = “Let me show you some restaurents”
return [SlotSet(“matches”, result)]
class Quoteform(FormAction):
def name(self):
return “quote_form”
@staticmethod
def required_slot(tracker:Tracker)->List[Text]:
return (["project_name","program_use","idea","application","money","contact"])
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 {"project_name": [self.from_text()],
"program_use": [self.from_text()],
"idea": [self.from_text()],
"application": [self.from_text()],
"money": [self.from_text()],
"contact": [self.from_text()]}
def submit(self,dispatcher : CollectingDispatcher,tracker:Tracker,domain :Dict[Text,Any]) -> List[Dict]:
dispatcher.utter_template('utter_send',tracker)
return []