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""" db = pymysql.connect('localhost', 'rasauser', 'rasapassword', 'rasa') cursor = db.cursor() name = tracker.get_slot('name') email = tracker.get_slot('email') password = tracker.get_slot('password') sql = f" INSERT INTO PERSON VALUES (NULL, '{name}', '{email}', '{password}')" try: cursor.execute(sql) db.commit() except pymysql.Error as exc: print("error inserting...\n {}".format(exc)) finally: db.close() # utter submit template dispatcher.utter_template('utter_submit', tracker) return []
def submit(self, dispatcher: CollectingDispatcher, tracker: Tracker, domain: Dict[Text, Any]) -> List[Dict]: # utter submit template dispatcher.utter_template('utter_submit', tracker) return []
def run(self, dispatcher: CollectingDispatcher, tracker: Tracker, domain: Dict[Text, Any]) -> List[Dict[Text, Any]]: #save in the slot the information that we got number_of_people = int(tracker.get_slot("num_persone")) orario = tracker.get_slot("orario") data = tracker.get_slot("data") prenotation_time = data + "T" + orario global number_of_seats service = authentication() if ":" == prenotation_time[-3:-2]: prenotation_time = prenotation_time[:-3] + prenotation_time[ -2:] # formattazione orario per chiamate successive prenotation_time_start = datetime.strptime(prenotation_time, '%Y-%m-%dT%H:%M:%S.%f%z') prenotation_time_end = prenotation_time_start + timedelta( hours=2) # si assume che una prenotazione duri 2 ore events_result = service.events().list( calendarId='*****@*****.**', timeMin=prenotation_time_start.isoformat(), timeMax=prenotation_time_end.isoformat()).execute() events = events_result.get('items', []) if check_available_seats( events, number_of_people ): # si controlla che ci siano posti disponibili dispatcher.utter_template("utter_confirmation", tracker) return [SlotSet('available_seats', True)] else: dispatcher.utter_message("Mi dispiace ma siamo al completo.") return [SlotSet('available_seats', False)]
def run(self, dispatcher: CollectingDispatcher, tracker: Tracker, domain: Dict[Text, Any]) -> List['Event']: intent_ranking = tracker.latest_message.get('intent_ranking', []) if len(intent_ranking) > 1: diff_intent_confidence = (intent_ranking[0].get("confidence") - intent_ranking[1].get("confidence")) if diff_intent_confidence < 0.2: intent_ranking = intent_ranking[:2] else: intent_ranking = intent_ranking[:1] first_intent_names = [ intent.get('name', '') for intent in intent_ranking if intent.get('name', '') != 'out_of_scope' ] message_title = "Sorry, I'm not sure I've understood " \ "you correctly 🤔 Do you mean..." mapped_intents = [(name, self.intent_mappings.get(name, name)) for name in first_intent_names] buttons = [] for intent in mapped_intents: buttons.append({ 'title': intent[1], 'payload': '/{}'.format(intent[0]) }) buttons.append({'title': 'Something else', 'payload': '/out_of_scope'}) dispatcher.utter_button_message(message_title, buttons=buttons) return []
def submit(self, dispatcher: CollectingDispatcher, tracker: Tracker, domain: Dict[Text, Any]) -> List[Dict]: """Once we have all the information, attempt to add it to the Google Drive database""" import datetime budget = tracker.get_slot('budget') company = tracker.get_slot('company') email = tracker.get_slot('business_email') job_function = tracker.get_slot('job_function') person_name = tracker.get_slot('person_name') use_case = tracker.get_slot('use_case') date = datetime.datetime.now().strftime("%d/%m/%Y") sales_info = [company, use_case, budget, date, person_name, job_function, email] gdrive = GDriveService() try: gdrive.store_data(sales_info) dispatcher.utter_template('utter_confirm_salesrequest', tracker) return [] except Exception as e: logger.error("Failed to write data to gdocs. Error: {}" "".format(e.message), exc_info=True) dispatcher.utter_template('utter_salesrequest_failed', tracker) return []
def _utter_event_overview(self, dispatcher: CollectingDispatcher) -> None: events = self._get_events() event_items = ["- {} in {}".format(e.name, e.location) for e in events] locations = "\n".join(event_items) dispatcher.utter_message("Here are the next Rasa events:\n" "" + locations + "\nWe hope to see you at them!")
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 == 'date': if self.date_validation(value) == False: dispatcher.utter_template('utter_wrong_date', tracker) 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()]
def run(self, dispatcher: CollectingDispatcher, tracker: Tracker, domain: Dict[Text, Any]) -> List['Event']: intent_ranking = tracker.latest_message.get('intent_ranking', []) first_intent_names = [ intent.get('name', '') for intent in intent_ranking[:2] if intent.get('name', '') not in ['deny', 'affirm', 'out_of_scope'] ] message_title = "Sorry, I'm not sure I've understood " \ "you correctly 🤔 Do you mean..." mapped_intents = [(name, self.intent_mappings.get(name, name)) for name in first_intent_names] buttons = [] for intent in mapped_intents: buttons.append({ 'title': intent[1], 'payload': '/{}'.format(intent[0]) }) buttons.append({'title': 'Something else', 'payload': '/deny'}) dispatcher.utter_button_message(message_title, buttons=buttons) return []
def validate(self, dispatcher: CollectingDispatcher, tracker: Tracker, domain: Dict[Text, Any]) -> List[Dict]: 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)) else: temp = tracker.get_latest_entity_values('PER') aux = None for i in temp: if i.lower() != "hola": aux = i aux2 = next(tracker.get_latest_entity_values('persona'), None) loc = next(tracker.get_latest_entity_values('LOC'), None) misc = next(tracker.get_latest_entity_values('MISC'), None) if aux is None and aux2 is not None: return [SlotSet('persona', aux2.title())] elif aux is not None and aux is not "Hola": return [SlotSet('persona', aux.title())] elif loc is not None: return [SlotSet('persona', loc)] elif misc is not None: return [SlotSet('persona', misc)] else: dispatcher.utter_message("Dime cómo te llamas") return [] return [SlotSet(slot, value) for slot, value in slot_values.items()]
def run(self, dispatcher: CollectingDispatcher, tracker: Tracker, domain: Dict[Text, Any]) -> List[Dict[Text, Any]]: user_ignore_count = 2 count = 0 tracker_list = [] while user_ignore_count > 0: event = tracker.events[count].get('event') if event == 'user': user_ignore_count = user_ignore_count - 1 if event == 'bot': tracker_list.append(tracker.events[count]) count = count - 1 i = len(tracker_list) - 1 while i >= 0: data = tracker_list[i].get('data') if data: if "buttons" in data: dispatcher.utter_message(text=tracker_list[i].get('text'), buttons=data["buttons"]) else: dispatcher.utter_message(text=tracker_list[i].get('text')) i -= 1 return []
def run(self, dispatcher: CollectingDispatcher, tracker: Tracker, domain: Dict[Text, Any]) -> List[Dict[Text, Any]]: province = tracker.get_slot('province') # build target_URL target_URL_suffix = "?image=" + config['images'][ province] + "&description=" + config['descriptions'][ province] + "&province=" + province target_URL = wv_URL + target_URL_suffix logging.warning("target_URL is " + str(target_URL)) # build JSON to be sent to Facebook Messenger based on province provided in Rasa chat message1 = { "attachment": { "type": "template", "payload": { "template_type": "button", "text": "click below to open webview", "buttons": [{ "type": "web_url", "url": target_URL, "title": province, "messenger_extensions": "true", "webview_height_ratio": "tall" }] } } } # send payload to Facebook Messenger and echo confirmation dispatcher.utter_custom_json(message1) return []
def submit(self, dispatcher: CollectingDispatcher, tracker: Tracker, domain: Dict[Text, Any]) -> List[Dict]: location_name = tracker.get_slot('location') cuisine = tracker.get_slot('cuisine') budget = tracker.get_slot('budget') top_5_restaurants = [] if self.lat is not None and self.lon is not None and self.cuisine_id is not None and self.budget_type is not None: top_5_restaurants = zomato_utils.get_top_restaurants_by_user_ratings(self.lat, self.lon, self.cuisine_id, self.budget_type) response = "No restaurants found in {} serving {} cuisine in {} budget".format(location_name, cuisine, budget) response_array = [] if len(top_5_restaurants) > 0: index = 1 response = "Following are top 5 restaurants matching your preference in order of average user rating on zomato:\n\n" for restaurant in top_5_restaurants: response = response + "{}. {} in {} has been rated {}\n".format(index, restaurant['name'], restaurant['address'], restaurant['user_rating']) index += 1 response_array = [SlotSet("lat", self.lat), SlotSet("lon", self.lon), SlotSet("cuisine_id", self.cuisine_id), SlotSet("budget_type", self.budget_type)] dispatcher.utter_message(response) return response_array
def validate(self, dispatcher: CollectingDispatcher, tracker: Tracker, domain: Dict[Text, Any]) -> List[Dict]: 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)) if not slot_values: raise ActionExecutionRejection(self.name(), "Failed to validate slot {0}" "with action {1}" "".format(slot_to_fill, self.name())) for slot, value in slot_values.items(): if slot == "TypeOfVehicle": if value not in self.TypeOfVehicle_db(): dispatcher.utter_template('utter_wrong_TypeOfVehicle', 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()]
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""" location = tracker.get_slot('location') speciality = tracker.get_slot('speciality') results = _find_providers(location, speciality) buttons = [] for r in results: provider_id = r.get("provider_id") provider_name = r.get("provider_name") payload = "/inform{\"provider_id\":\"" + provider_id + "\"}" buttons.append({ "title": "{}".format(provider_name.title()), "payload": payload }) # limit number of buttons to 3 here for clear presentation purpose dispatcher.utter_button_message( "Here is a list of {} {} near you".format(len(buttons[:3]), "providers"), buttons[:3], button_type="vertical") # todo: note: button options are not working BUG in rasa_core # utter submit template dispatcher.utter_template('utter_submit', tracker) return []
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""" # utter submit template dispatcher.utter_template('utter_submit', tracker) return []
def test_extract_other_slots_with_intent(): """Test extraction of other not requested slots values from entities with the same names """ # noinspection PyAbstractClass class CustomFormAction(FormAction): def name(self): return "some_form" @staticmethod def required_slots(_tracker): return ["some_slot", "some_other_slot"] def slot_mappings(self): return { "some_other_slot": self.from_entity( entity="some_other_slot", intent="some_intent" ) } form = CustomFormAction() tracker = Tracker( "default", {"requested_slot": "some_slot"}, { "intent": {"name": "some_other_intent", "confidence": 1.0}, "entities": [{"entity": "some_other_slot", "value": "some_other_value"}], }, [], False, None, {}, "action_listen", ) slot_values = form.extract_other_slots(CollectingDispatcher(), tracker, {}) # check that the value was extracted for non requested slot assert slot_values == {} tracker = Tracker( "default", {"requested_slot": "some_slot"}, { "intent": {"name": "some_intent", "confidence": 1.0}, "entities": [{"entity": "some_other_slot", "value": "some_other_value"}], }, [], False, None, {}, "action_listen", ) slot_values = form.extract_other_slots(CollectingDispatcher(), tracker, {}) # check that the value was extracted only for non requested slot assert slot_values == {"some_other_slot": "some_other_value"}
def test_extract_trigger_slots(): """Test extraction of a slot value from trigger intent """ # noinspection PyAbstractClass class CustomFormAction(FormAction): def name(self): return "some_form" @staticmethod def required_slots(_tracker): return ['some_slot'] def slot_mappings(self): return { "some_slot": self.from_trigger_intent(intent="trigger_intent", value="some_value") } form = CustomFormAction() tracker = Tracker( 'default', {}, {'intent': { 'name': 'trigger_intent', 'confidence': 1.0 }}, [], False, None, {}, 'action_listen') slot_values = form.extract_other_slots(CollectingDispatcher(), tracker, {}) # check that the value was extracted for correct intent assert slot_values == {'some_slot': 'some_value'} tracker = Tracker('default', {}, {'intent': { 'name': 'other_intent', 'confidence': 1.0 }}, [], False, None, {}, 'action_listen') slot_values = form.extract_other_slots(CollectingDispatcher(), tracker, {}) # check that the value was not extracted for incorrect intent assert slot_values == {} # tracker with active form tracker = Tracker( 'default', {}, {'intent': { 'name': 'trigger_intent', 'confidence': 1.0 }}, [], False, None, { 'name': 'some_form', 'validate': True, 'rejected': False }, 'action_listen') slot_values = form.extract_other_slots(CollectingDispatcher(), tracker, {}) # check that the value was not extracted for correct intent assert slot_values == {}
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 == 'crop' or slot == 'product': if value.lower() not in self.cuisine_db(): dispatcher.utter_template('utter_wrong_cuisine', tracker) # validation failed, set slot to None slot_values[slot] = None # elif slot == 'num_people': # if not self.is_int(value) or int(value) <= 0: # dispatcher.utter_template('utter_wrong_num_people', # tracker) # # validation failed, set slot to None # slot_values[slot] = None # elif slot == 'outdoor_seating': # if isinstance(value, str): # if 'out' in value: # # convert "out..." to True # slot_values[slot] = True # elif 'in' in value: # # convert "in..." to False # slot_values[slot] = False # else: # dispatcher.utter_template('utter_wrong_outdoor_seating', # 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()]
def validate_num_persone(self, value: Text, dispatcher: CollectingDispatcher, tracker: Tracker, domain: Dict[Text, Any]): if self.is_int(value): return value else: dispatcher.utter_template('utter_default_incomprensione', tracker) return None
def test_extract_requested_slot_from_text_with_not_intent(): """Test extraction of a slot value from text with certain intent """ # noinspection PyAbstractClass class CustomFormAction(FormAction): def name(self): return "some_form" def slot_mappings(self): return {"some_slot": self.from_text(not_intent="some_intent")} form = CustomFormAction() tracker = Tracker( "default", {"requested_slot": "some_slot"}, { "text": "some_text", "intent": { "name": "some_intent", "confidence": 1.0 } }, [], False, None, {}, "action_listen", ) slot_values = form.extract_requested_slot(CollectingDispatcher(), tracker, {}) # check that the value was extracted for correct intent assert slot_values == {} tracker = Tracker( "default", {"requested_slot": "some_slot"}, { "text": "some_text", "intent": { "name": "some_other_intent", "confidence": 1.0 }, }, [], False, None, {}, "action_listen", ) slot_values = form.extract_requested_slot(CollectingDispatcher(), tracker, {}) # check that the value was not extracted for incorrect intent assert slot_values == {"some_slot": "some_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""" """in other words from here the applicant data goes to the database""" # utter submit template dispatcher.utter_template('action_store_applicant', tracker) return []
def submit(self, dispatcher: CollectingDispatcher, tracker: Tracker, domain: Dict[Text, Any]) -> List[Dict]: persona = tracker.get_slot('persona') if persona is not None: dispatcher.utter_template("utter_saludo_nombre", tracker, **tracker.slots) return [SlotSet('persona', persona)] else: dispatcher.utter_template("utter_saludo", tracker) return []
def validate_cv_link(value: Text, dispatcher: CollectingDispatcher, tracker: Tracker, domain: Dict[Text, Any]) -> Any: CV_LINK_REGEX = re.compile(r'''[https:\/\/]*[www.]*linkedin.[com | org | tn | fr | me]+[\\/in\\/]*[a-z A-z 0-9 -]+''') if CV_LINK_REGEX.match(value): return value else: dispatcher.utter_template('utter_wrong_cv_link', tracker) # validation failed, set slot to None return None
def validate_stars(self, value: Text, dispatcher: CollectingDispatcher, tracker: Tracker, domain: Dict[Text, Any]) -> Optional[Text]: """Validate stars value.""" if self.is_int(value) and int(value) > 0 and int(value) < 6: return {"stars": value} else: dispatcher.utter_template('utter_wrong_stars', tracker) # validation failed, set slot to None return {"stars": None}
def validate_num_people(self, value: Text, dispatcher: CollectingDispatcher, tracker: Tracker, domain: Dict[Text, Any]) -> Optional[Text]: """Validate num_people value.""" if self.is_int(value) and int(value) > 0: return value else: dispatcher.utter_template('utter_wrong_num_people', tracker) # validation failed, set slot to None return None
def validate_cuisine(self, value: Text, dispatcher: CollectingDispatcher, tracker: Tracker, domain: Dict[Text, Any]) -> Optional[Text]: cuisine = zomato_utils.get_valid_cuisine(value) if cuisine['is_valid']: self.cuisine_id = cuisine["cuisine_id"] return value else: dispatcher.utter_template('utter_wrong_cuisine', tracker) return None
def validate_email(value: Text, dispatcher: CollectingDispatcher, tracker: Tracker, domain: Dict[Text, Any]) -> Any: EMAIL_REGEX = re.compile(r"[a-z A-Z]+[0-9 a-z A-Z]*@[a-z A-Z]+[.][a-z A-Z]+") if EMAIL_REGEX.match(value): return value else: dispatcher.utter_template('utter_wrong_email', tracker) # validation failed, set slot to None return None
def validate_budget(self, value: Text, dispatcher: CollectingDispatcher, tracker: Tracker, domain: Dict[Text, Any]) -> Optional[Text]: budget = zomato_utils.get_valid_budget(value) if budget['is_valid']: self.budget_type = budget["type"] return value else: dispatcher.utter_template('utter_wrong_budget', tracker) return None
def validate_position(self, value: Text, dispatcher: CollectingDispatcher, tracker: Tracker, domain: Dict[Text, Any]) -> Optional[Text]: if value.lower() in self.position_db(): # validation succeeded return {"position": value} else: dispatcher.utter_template('utter_wrong_option', tracker) # validation failed, set this slot to None, meaning the # user will be asked for the slot again return {"position": None}
def test_validate(): # noinspection PyAbstractClass class CustomFormAction(FormAction): def name(self): return "some_form" @staticmethod def required_slots(_tracker): return ["some_slot", "some_other_slot"] form = CustomFormAction() tracker = Tracker('default', {'requested_slot': 'some_slot'}, { 'entities': [{ 'entity': 'some_slot', 'value': 'some_value' }, { 'entity': 'some_other_slot', 'value': 'some_other_value' }] }, [], False, None, {}, 'action_listen') events = form.validate(CollectingDispatcher(), tracker, {}) # check that validation succeed assert (events == [ SlotSet('some_other_slot', 'some_other_value'), SlotSet('some_slot', 'some_value') ] or events == [ SlotSet('some_slot', 'some_value'), SlotSet('some_other_slot', 'some_other_value') ]) tracker = Tracker('default', {'requested_slot': 'some_slot'}, { 'entities': [{ 'entity': 'some_other_slot', 'value': 'some_other_value' }] }, [], False, None, {}, 'action_listen') events = form.validate(CollectingDispatcher(), tracker, {}) # check that validation succeed because other slot was extracted assert events == [SlotSet('some_other_slot', 'some_other_value')] tracker = Tracker('default', {'requested_slot': 'some_slot'}, {'entities': []}, [], False, None, {}, 'action_listen') with pytest.raises(Exception) as execinfo: form.validate(CollectingDispatcher(), tracker, {}) # check that validation failed gracefully assert execinfo.type == ActionExecutionRejection assert ("Failed to validate slot some_slot " "with action some_form" in str(execinfo.value))