def process_input(self, utterance, dialogue_state=None):
        """
        Process the utterance and see if any intent pattern matches.

        :param utterance: a string, the utterance to be recognised
        :param dialogue_state: the current dialogue state, if available
        :return: a list of recognised dialogue acts
        """
        dacts = []
        dact = DialogueAct('UNK', [])

        # TODO: Remove this once nlg is updated
        utterance = utterance.replace('<PAD>', '')

        if not utterance:
            return [dact]

        last_sys_act = \
            dialogue_state.last_sys_acts[0] \
            if dialogue_state and dialogue_state.last_sys_acts else None

        utterance = utterance.rstrip().lower()
        utterance = utterance.translate(self.punctuation_remover)

        # Replace synonyms
        utterance = utterance.replace('location', 'area')
        utterance = utterance.replace('part of town', 'area')
        utterance = utterance.replace('center', 'centre')
        utterance = utterance.replace('cheaply', 'cheap')
        utterance = utterance.replace('moderately', 'moderate')
        utterance = utterance.replace('expensively', 'expensive')
        utterance = utterance.replace('address', 'addr')
        utterance = utterance.replace('telephone', 'phone')
        utterance = utterance.replace('postal code', 'postcode')
        utterance = utterance.replace('post code', 'postcode')
        utterance = utterance.replace('zip code', 'postcode')
        utterance = utterance.replace('price range', 'pricerange')

        # First check if the user doesn't care
        if last_sys_act and last_sys_act.intent in ['request', 'expl-conf']:
            for p in self.dontcare_pattern:
                # Look for exact matches here only (i.e. user just says
                # 'i don't care')
                if p == utterance:
                    dact.intent = 'inform'
                    dact.params.append(
                        DialogueActItem(
                            last_sys_act.params[0].slot,
                            Operator.EQ,
                            'dontcare'))

                    return [dact]

        # Look for slot keyword and corresponding value
        words = utterance.split(' ')

        for p in self.ack_pattern:
            if p == utterance:
                dact.intent = 'ack'
                break

        for p in self.deny_pattern:
            if p == utterance:
                dact.intent = 'deny'
                break

        for p in self.affirm_pattern:
            if p == utterance:
                dact.intent = 'affirm'
                break

        # Check for dialogue ending
        for p in self.bye_pattern:
            match = re.search(r'\b{0}\b'.format(p), utterance)
            if match:
                dact.intent = 'bye'
                break

        # Search for 'welcome' first because it may contain 'hello'
        if dact.intent == 'UNK':
            for p in self.welcome_pattern:
                match = re.search(r'\b{0}\b'.format(p), utterance)
                if match:
                    dact.intent = 'welcomemsg'
                    break

        if dact.intent == 'UNK':
            for p in self.hi_pattern:
                match = re.search(r'\b{0}\b'.format(p), utterance)
                if match:
                    dact.intent = 'hello'
                    break

        if dact.intent == 'UNK':
            for p in self.reqalts_pattern:
                match = re.search(r'\b{0}\b'.format(p), utterance)
                if match:
                    dact.intent = 'reqalts'
                    break

        if dact.intent == 'UNK':
            for p in self.reqmore_pattern:
                match = re.search(r'\b{0}\b'.format(p), utterance)
                if match:
                    dact.intent = 'reqmore'
                    break

        if dact.intent == 'UNK':
            for p in self.repeat_pattern:
                match = re.search(r'\b{0}\b'.format(p), utterance)
                if match:
                    dact.intent = 'repeat'
                    break

        if dact.intent == 'UNK':
            for p in self.restart_pattern:
                match = re.search(r'\b{0}\b'.format(p), utterance)
                if match:
                    dact.intent = 'restart'
                    break

        if dact.intent == 'UNK':
            for p in self.thankyou_pattern:
                match = re.search(r'\b{0}\b'.format(p), utterance)
                if match:
                    dact.intent = 'thankyou'
                    break

        if dact.intent == 'UNK':
            for p in self.request_pattern:
                match = re.search(r'\b{0}\b'.format(p), utterance)
                if match:
                    dact.intent = 'request'
                    break

        if dact.intent == 'UNK':
            for p in self.select_pattern:
                match = re.search(r'\b{0}\b'.format(p), utterance)
                if match:
                    dact.intent = 'select'
                    break

        if dact.intent == 'UNK':
            for p in self.confirm_pattern:
                match = re.search(r'\b{0}\b'.format(p), utterance)
                if match:
                    dact.intent = 'confirm'
                    break

        if dact.intent == 'UNK':
            for p in self.expl_conf_pattern:
                match = re.search(r'\b{0}\b'.format(p), utterance)
                if match:
                    dact.intent = 'expl-conf'
                    break

        if dact.intent == 'UNK':
            for p in self.cant_help_pattern:
                match = re.search(r'\b{0}\b'.format(p), utterance)
                if match:
                    dact.intent = 'canthelp'
                    dact.params = []
                    return [dact]

        if dact.intent == 'UNK':
            dact.intent = 'inform'

            # Check if there is no information about the slot
            if 'no info' in utterance:
                # Search for a slot name in the utterance
                for slot in self.ontology.ontology['requestable']:
                    if slot in utterance:
                        dact.params.append(
                            DialogueActItem(slot, Operator.EQ, 'no info'))
                        return [dact]

                # Else try to grab slot name from the other agent's
                # previous act
                if last_sys_act and \
                        last_sys_act.intent in ['request', 'expl-conf']:
                    dact.params.append(
                        DialogueActItem(
                            last_sys_act.params[0].slot,
                            Operator.EQ,
                            'dontcare'))

                    return [dact]

                # Else do nothing, and see if anything matches below

        if dact.intent in ['inform', 'request']:
            for word in words:
                # Check for requests. Requests for informable slots are
                # captured below
                if word in self.requestable_only_slots:
                    if dact.intent == 'request':
                        dact.params.append(
                            DialogueActItem(word, Operator.EQ, ''))
                        break

                    elif word != 'name':
                        if 'is' not in utterance and 'its' not in utterance:
                            dact.intent = 'request'
                            dact.params.append(
                                DialogueActItem(word, Operator.EQ, ''))
                            break

                        # For any other kind of intent, we have no way of
                        # determining the slot's value, since such
                        # information is not in the ontology.

                # Check for informs (most intensive)
                if word in self.ontology.ontology['informable']:

                    # If a request intent has already been recognized,
                    # do not search for slot values
                    if dact.intent == 'request':
                        dact.params.append(
                            DialogueActItem(word, Operator.EQ, ''))
                        break

                    found = False

                    for p in self.ontology.ontology['informable'][word]:
                        match = re.search(r'\b{0}\b'.format(p), utterance)
                        if match:
                            if word == 'name':
                                dact.intent = 'offer'
                            else:
                                dact.intent = 'inform'

                            dact.params.append(
                                DialogueActItem(word, Operator.EQ, p))
                            found = True
                            break

                    if not found:
                        # Search for dontcare (e.g. I want any area)
                        for p in self.dontcare_pattern:
                            match = re.search(r'\b{0}\b'.format(p), utterance)
                            if match:
                                dact.intent = 'inform'
                                dact.params.append(
                                    DialogueActItem(
                                        word,
                                        Operator.EQ,
                                        'dontcare'))

                                return [dact]

                        dact.intent = 'request'
                        dact.params.append(
                            DialogueActItem(word, Operator.EQ, ''))

        # If nothing was recognised, do an even more brute-force search
        if dact.intent in ['UNK', 'inform'] and not dact.params:
            slot_vals = self.ontology.ontology['informable']
            if self.slot_values:
                slot_vals = self.slot_values

            for slot in slot_vals:
                for value in slot_vals[slot]:
                    if value and \
                            value.lower().translate(self.punctuation_remover) \
                            in utterance:
                        if slot == 'name':
                            dact.intent = 'offer'

                        di = DialogueActItem(slot, Operator.EQ, value)

                        if di not in dact.params:
                            dact.params.append(di)

        # Check if something has been missed (e.g. utterance is dont care and
        # there's no previous sys act)
        if dact.intent == 'inform':
            # Check to see that all slots have an identified value
            if dact.params:
                for dact_item in dact.params:
                    if not dact_item.slot or not dact_item.value:
                        dact.params.remove(dact_item)

                        if not dact.params:
                            dact.intent = 'UNK'
                            break

                    # Else, break up the inform into several acts
                    elif dact_item.slot == 'name':
                        dacts.append(DialogueAct('offer', [dact_item]))
                    else:
                        dacts.append(DialogueAct('inform', [dact_item]))
            else:
                # Try to see if the utterance refers to a slot in the
                # requestable ones (e.g. 'I prefer any phone')
                for slot in self.ontology.ontology['requestable']:
                    if slot in utterance:
                        # We can only handle 'dontcare' kind of values here,
                        # as we do not know values of req. slots.
                        for p in self.dontcare_pattern:
                            match = re.search(r'\b{0}\b'.format(p), utterance)
                            if match:
                                dact.params = \
                                    [DialogueActItem(
                                        slot,
                                        Operator.EQ,
                                        'dontcare')]

                dact.intent = 'UNK'

        else:
            dacts.append(dact)

        return dacts

        Process the utterance and see if any intent pattern matches.

        :param utterance: a string, the utterance to be recognised
        :param dialogue_state: the current dialogue state, if available
        :return: a list of recognised dialogue acts
        
plato/agent/component/nlu/slot_filling_nlu.py