Exemplo n.º 1
0
    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 []
Exemplo n.º 2
0
 def submit(self,
            dispatcher: CollectingDispatcher,
            tracker: Tracker,
            domain: Dict[Text, Any]) -> List[Dict]:
     # utter submit template
     dispatcher.utter_template('utter_submit', tracker)
     return []
Exemplo n.º 3
0
    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)]
Exemplo n.º 4
0
    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 []
Exemplo n.º 5
0
    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 []
Exemplo n.º 6
0
 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!")
Exemplo n.º 7
0
    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()]
Exemplo n.º 8
0
    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 []
Exemplo n.º 9
0
    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()]
Exemplo n.º 10
0
    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 []
Exemplo n.º 11
0
    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 []
Exemplo n.º 12
0
    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
Exemplo n.º 13
0
    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()]
Exemplo n.º 14
0
    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 []
Exemplo n.º 15
0
    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 []
Exemplo n.º 16
0
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"}
Exemplo n.º 17
0
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 == {}
Exemplo n.º 18
0
    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
Exemplo n.º 20
0
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"}
Exemplo n.º 21
0
 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 []
Exemplo n.º 22
0
 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 []
Exemplo n.º 23
0
 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
Exemplo n.º 24
0
    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}
Exemplo n.º 25
0
    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
Exemplo n.º 26
0
 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
Exemplo n.º 27
0
    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
Exemplo n.º 28
0
 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
Exemplo n.º 29
0
    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}
Exemplo n.º 30
0
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))