Hi i am using rasa open source:
Rasa Version : 2.8.12 Minimum Compatible Version: 2.8.9 Rasa SDK Version : 2.8.1 Rasa X Version : None Python Version : 3.8.0 Operating System : Windows-10-10.0.19041-SP0
i want deactivate the form after the user enter software that is not listed in standard_software. instead of keep on asking the next required_slot the bot should just send the link to user fill in the website but it keep on asking the next slot to fill in by the user. how do i fixed this?
from logging import Logger
from typing import Any, Text, Dict, List, Union, Optional
from rasa_sdk import Action, Tracker
from rasa_sdk.executor import CollectingDispatcher
from rasa_sdk.events import SlotSet, AllSlotsReset, EventType
from rasa_sdk.forms import REQUESTED_SLOT, FormValidationAction
import re
from rasa_sdk.interfaces import ActionExecutionRejection
from rasa_sdk.types import DomainDict
from actions.utils import validate_email_address, validate_asset_tag_no
class ValidateSoftwareInstallationForm(FormValidationAction):
"""Form action to raise a software installation request"""
#TODO: Implement lookup
standard_software = [
"MS Office",
"MS Project",
"MS Visio",
"Acrobat Writer",
"IBM Personal Communications",
"Acrobat Reader",
"Java 6",
"Google Chrome",
"Lotus Notes 6.5.3",
"Webex",
"7 Zip",
"SAPGUI",
"FireEye",
"Zoom Apps",
"VMware Horizon Client",
"TeamMate application",
"Citrix Netscaler Gateaway"
]
def name(self) -> Text:
"""Unique identifier of the form"""
return "validate_software_installation_form"
@staticmethod
async def required_slots(
self,
#slots_mapped_in_domain: List[Text],
dispatcher: "CollectingDispatcher",
tracker: "Tracker",
domain: "DomainDict",
) -> Optional[List[Text]]:
required_slots = [
"software",
"location",
"purpose",
"asset_tag",
"approver",
# "department"
]
if tracker.get_slot("req_subject") == "other":
required_slots.insert(0,"pf_number")
if tracker.get_slot("software") in ValidateSoftwareInstallationForm.standard_software:
required_slots.append("cost_centre")
else:
#required_slots.extend([
#"soft_background",
#"usage_duration"
# ])
return required_slots
def slot_mappings(self) -> 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 {
"software": [
self.from_entity(entity="software", intent="install_software"),
self.from_entity(entity="software", intent="inform"),
],
"pf_number": [
#self.from_entity(entity="pf_number", intent="inform"),
self.from_entity(entity="pf_number", intent="inform"),
],
# "department": [
# self.from_entity(entity="department", intent="inform"),
# ],
"location": [
self.from_entity(entity="location", intent="inform"),
#self.from_entity(entity="location"),
#self.from_text(),
],
"purpose": self.from_entity(entity="purpose", intent="inform"),
"asset_tag": self.from_entity(entity="asset_tag", intent="inform"),
"approver": [
self.from_entity(entity="email", intent="inform"),
#self.from_text(),
],
"soft_background": self.from_entity(entity="soft_background", intent="inform"),
"usage_duration": self.from_entity(entity="usage_duration", intent="inform"),
"cost_centre": self.from_entity(entity="cost_centre", intent="inform"),
}
def request_next_slot(
self,
dispatcher: "CollectingDispatcher",
tracker: "Tracker",
domain: Dict[Text, Any],
) -> Optional[List[EventType]]:
"""Request the next slot and utter template if needed, else return None"""
for slot in self.required_slots(tracker):
if self._should_request_slot(tracker, slot):
# Show the standard software list
if slot == "software":
buttons = []
for software in ValidateSoftwareInstallationForm.standard_software:
payload = "/inform{\"software\":\"" + software + "\"}"
buttons.append(
#{"title": software, "payload": payload}
{"title":software, "payload": payload}
)
message = "What software would you like to install? " + \
"Please choose from this list of standard software or key in your non-standard software."
#super.logger.debug("Requesting software slot")
dispatcher.utter_message(
text=message,
buttons=buttons)
else:
#super.logger.debug(f"Request next slot '{slot}'")
dispatcher.utter_message(template=f"utter_ask_{slot}", **tracker.slots)
return [SlotSet("requested_slot", slot)]
# no more required slots to fill
return None
@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_software(
self,
value: Text,
dispatcher: CollectingDispatcher,
tracker: Tracker,
domain: Dict[Text, Any],
) -> Dict[Text, Any]:
"Display non-standard software info"
if value not in ValidateSoftwareInstallationForm.standard_software:
message = "As your requested software is not in the standard usage list, " + \
"please submit your request on the website"
dispatcher.utter_message(text=message)
return {"software": value}
#return self.deactivate()
def validate_pf_number(
self,
value: Text,
dispatcher: CollectingDispatcher,
tracker: Tracker,
domain: Dict[Text, Any],
) -> Dict[Text, Any]:
"""Validate PF number."""
#print("Check if " + value + " is valid PF.")
if self.is_int(value) and len(value) == 8:
# validation succeeded, set the value of the "cuisine" slot to value
#print("PF number valid")
return {"pf_number": value}
else:
dispatcher.utter_message(template="utter_wrong_pf_format")
# validation failed, set this slot to None, meaning the
# user will be asked for the slot again
return {"pf_number": None}
def validate_asset_tag(
self,
value: Text,
dispatcher: CollectingDispatcher,
tracker: Tracker,
domain: Dict[Text, Any],
) -> Dict[Text, Any]:
"""Validate asset tag number"""
if validate_asset_tag_no(value=value, dispatcher=dispatcher):
return {"asset_tag": value}
else:
return {"asset_tag": None}
def validate_approver(
self,
value: Text,
dispatcher: CollectingDispatcher,
tracker: Tracker,
domain: Dict[Text, Any],
) -> Dict[Text, Any]:
"""Check that approver email is valid email address"""
if validate_email_address(email=value, dispatcher=dispatcher):
return {"approver": value}
else:
return {"approver": None}
# #TODO: Check with People Directory if approver is valid
# email_regex = '^\w+([\.-]?\w+)*@\w+([\.-]?\w+)*(\.\w{2,3})+$'
# if re.search(email_regex,value):
# return {"approver": value}
# else:
# dispatcher.utter_message(text="Sorry, that is not a valid email address. Please try again.")
# return {"approver": None}
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"""
slots = tracker.current_slot_values()
software = slots['software']
location = slots['location']
purpose = slots['purpose']
asset_tag = slots['asset_tag']
approver = slots['approver']
dispatcher.utter_message("Here are your ticket details.")
dispatcher.utter_message("Software: " + software)
dispatcher.utter_message("Purpose: " + purpose)
dispatcher.utter_message("Asset tag: " + asset_tag)
dispatcher.utter_message("Location: " + location)
dispatcher.utter_message("Approver Email: " + approver)
buttons = [
{"title": "Yes", "payload": "/affirm"},
{"title": "No", "payload": "/deny"}
]
dispatcher.utter_message(text="Shall I submit?", buttons=buttons)
return []