Kaynağa Gözat

start refactoring. Split Orader Analyser from ParameterLoader and NeuronLauncher

nico 8 yıl önce
ebeveyn
işleme
6373968dad

+ 102 - 0
kalliope/OrderAnalyser2.py

@@ -0,0 +1,102 @@
+# coding: utf8
+import collections
+from collections import Counter
+
+from kalliope.core.Utils.Utils import Utils
+from kalliope.core.ConfigurationManager import SettingLoader
+from kalliope.core.Models import Order
+
+import logging
+
+logging.basicConfig()
+logger = logging.getLogger("kalliope")
+
+
+class OrderAnalyser2:
+    """
+    This Class is used to get a list of synapses that match a given Spoken order
+    """
+
+    brain = None
+    settings = None
+
+    @classmethod
+    def __init__(cls):
+        cls.settings = SettingLoader().settings
+
+    @classmethod
+    def get_matching_synapse(cls, order, brain=None):
+        cls.brain = brain
+        logger.debug("[OrderAnalyser] Received order: %s" % order)
+        if isinstance(order, str):
+            order = order.decode('utf-8')
+
+        # test each synapse from the brain
+        for synapse in cls.brain.synapses:
+            # we are only concerned by synapse with a order type of signal
+            for signal in synapse.signals:
+                if type(signal) == Order:
+                    if cls.spelt_order_match_brain_order_via_table(signal.sentence, order):
+                        # the order match the synapse, we add it to the returned list
+                        logger.debug("Order found! Run neurons: %s" % neuron.name for neuron in synapse.neurons)
+                        Utils.print_success("Order matched in the brain. Running synapse \"%s\"" % synapse.name)
+                        # we need to keep the info about which order in the list of signal has match.
+                        # We use a namedtuple to associate the synapse and the signal of the synapse
+                        synapse_order_tuple = collections.namedtuple('tuple_synapse_matchingOrder',
+                                                                     ['synapse', 'order'])
+                        # we don't need to store the synapse in a list. Use a generator instead
+                        yield synapse_order_tuple(synapse=synapse, order=signal.sentence)
+
+    @classmethod
+    def spelt_order_match_brain_order_via_table(cls, order_to_analyse, user_said):
+        """
+        return true if all formatted(_format_sentences_to_analyse(order_to_analyse, user_said)) strings
+                that are in the sentence are present in the order to test.
+        :param order_to_analyse: String order to test
+        :param user_said: String to compare to the order
+        :return: True if all string are present in the order
+        """
+        # Lowercase all incoming
+        order_to_analyse = order_to_analyse.lower()
+        user_said = user_said.lower()
+
+        logger.debug("[spelt_order_match_brain_order_via_table] "
+                     "order to analyse: %s, "
+                     "user sentence: %s"
+                     % (order_to_analyse, user_said))
+
+        list_word_user_said = user_said.split()
+        split_order_without_bracket = cls._get_split_order_without_bracket(order_to_analyse)
+
+        # if all words in the list of what the user said in in the list of word in the order
+        return cls._counter_subset(split_order_without_bracket, list_word_user_said)
+
+    @staticmethod
+    def _get_split_order_without_bracket(order):
+        """
+        Get an order with bracket inside like: "hello my name is {{ name }}.
+        return a list of string without bracket like ["hello", "my", "name", "is"]
+        :param order: sentence to split
+        :return: list of string without bracket
+        """
+
+        matches = Utils.find_all_matching_brackets(order)
+        for match in matches:
+            order = order.replace(match, "")
+        # then split
+        split_order = order.split()
+        return split_order
+
+    @staticmethod
+    def _counter_subset(list1, list2):
+        """
+        check if the number of occurrences matches
+        :param list1:
+        :param list2:
+        :return:
+        """
+        c1, c2 = Counter(list1), Counter(list2)
+        for k, n in c1.items():
+            if n > c2[k]:
+                return False
+        return True

+ 41 - 0
kalliope/core/NeuronLauncher.py

@@ -32,3 +32,44 @@ class NeuronLauncher:
                                                      parameters=neuron.parameters,
                                                      resources_dir=neuron_folder)
 
+    @classmethod
+    def start_neuron_list(cls, neuron_list, parameters_dict):
+        """
+        Execute each neuron from the received neuron_list.
+        Replace parameter if existe in the received dict of parameters_dict
+        :param neuron_list: list of Neuron object to run
+        :param parameters_dict: dict of parameter to load in each neuron if expecting a parameter
+        :return:
+        """
+        for neuron in neuron_list:
+
+            problem_in_neuron_found = False
+            if isinstance(neuron.parameters, dict):
+                # print neuron.parameters
+                if "args" in neuron.parameters:
+                    logger.debug("The neuron waits for parameter")
+                    # check that the user added parameters to his order
+                    if parameters_dict is None:
+                        # we don't raise an error and break the program but we don't run the neuron
+                        problem_in_neuron_found = True
+                        Utils.print_danger("Error: The neuron %s is waiting for argument. "
+                                           "Argument found in bracket in the given order" % neuron.name)
+                    else:
+                        # we add wanted arguments the existing neuron parameter dict
+                        for arg in neuron.parameters["args"]:
+                            if arg in parameters_dict:
+                                logger.debug("Parameter %s added to the current parameter "
+                                             "of the neuron: %s" % (arg, neuron.name))
+                                neuron.parameters[arg] = parameters_dict[arg]
+                            else:
+                                # we don't raise an error and break the program but
+                                # we don't run the neuron
+                                problem_in_neuron_found = True
+                                Utils.print_danger("Error: Argument \"%s\" not found in the"
+                                                   " order" % arg)
+
+            # if no error detected, we run the neuron
+            if not problem_in_neuron_found:
+                cls.start_neuron(neuron)
+            else:
+                Utils.print_danger("A problem has been found in the Synapse.")

+ 65 - 0
kalliope/core/NeuronParameterLoader.py

@@ -0,0 +1,65 @@
+from kalliope import Utils
+
+import logging
+
+logging.basicConfig()
+logger = logging.getLogger("kalliope")
+
+
+class NeuronParameterLoader(object):
+
+    @classmethod
+    def get_parameters(cls, synapse_order, user_order):
+        """
+        Class method to get all params coming from a string order. Returns a dict of key/value.
+        """
+        params = dict()
+        if Utils.is_containing_bracket(synapse_order):
+            params = cls._associate_order_params_to_values(user_order, synapse_order)
+            logger.debug("Parameters for order: %s" % params)
+        yield params
+
+    @staticmethod
+    def _associate_order_params_to_values(order, order_to_check):
+        """
+        Associate the variables from the order to the incoming user order
+        :param order_to_check: the order to check incoming from the brain
+        :type order_to_check: str
+        :param order: the order from user
+        :type order: str
+        :return: the dict corresponding to the key / value of the params
+        """
+        logger.debug("[OrderAnalyser._associate_order_params_to_values] user order: %s, "
+                     "order from synapse: %s" % (order, order_to_check))
+
+        list_word_in_order = Utils.remove_spaces_in_brackets(order_to_check).split()
+
+        # get the order, defined by the first words before {{
+        # /!\ Could be empty if order starts with double brace
+        the_order = order_to_check[:order_to_check.find('{{')]
+
+        # remove sentence before order which are sentences not matching anyway
+        # Manage Upper/Lower case
+        truncate_user_sentence = order[order.lower().find(the_order.lower()):]
+        truncate_list_word_said = truncate_user_sentence.split()
+
+        # make dict var:value
+        dict_var = dict()
+        for idx, ow in enumerate(list_word_in_order):
+            if Utils.is_containing_bracket(ow):
+                # remove bracket and grab the next value / stop value
+                var_name = ow.replace("{{", "").replace("}}", "")
+                stop_value = Utils.get_next_value_list(list_word_in_order[idx:])
+                if stop_value is None:
+                    dict_var[var_name] = " ".join(truncate_list_word_said)
+                    break
+                for word_said in truncate_list_word_said:
+                    if word_said == stop_value:
+                        break
+                    if var_name in dict_var:
+                        dict_var[var_name] += " " + word_said
+                        truncate_list_word_said = truncate_list_word_said[1:]
+                    else:
+                        dict_var[var_name] = word_said
+            truncate_list_word_said = truncate_list_word_said[1:]
+        return dict_var