Browse Source

core now use the LIFO for launching synapses

nico 8 years ago
parent
commit
f3d87e6371

+ 3 - 2
kalliope/__init__.py

@@ -124,9 +124,10 @@ def main():
                                           brain=brain)
 
         if args.run_order is not None:
-            SynapseLauncher.run_matching_synapse_or_default(args.run_order,
+            SynapseLauncher.run_matching_synapse_from_order(args.run_order,
                                                             brain=brain,
-                                                            settings=settings)
+                                                            settings=settings,
+                                                            is_api_call=False)
 
         if (args.run_synapse is None) and (args.run_order is None):
             # first, load events in event manager

+ 2 - 1
kalliope/core/MainController.py

@@ -196,7 +196,8 @@ class MainController:
         Start the order analyser with the caught order to process
         """
         logger.debug("order in analysing_order_thread %s" % self.order_to_process)
-        SynapseLauncher.run_matching_synapse_or_default(self.order_to_process, self.brain, self.settings)
+        SynapseLauncher.run_matching_synapse_from_order(self.order_to_process, self.brain,
+                                                        self.settings, is_api_call=False)
 
         # return to the state "unpausing_trigger"
         self.unpause_trigger()

+ 1 - 1
kalliope/core/Models/APIResponse.py

@@ -24,6 +24,6 @@ class APIResponse(object):
 
         return {
             'user_order': self.user_order,
-            'list_processed_matched_synapse': [e.serialize() for e in self.list_processed_matched_synapse],
+            'matched_synapses': [e.serialize() for e in self.list_processed_matched_synapse],
             'status': self.status
         }

+ 13 - 8
kalliope/core/Models/LIFOBuffer.py

@@ -35,7 +35,7 @@ class LIFOBuffer(object):
         cls.lifo_list.append(matched_synapse_list)
 
     @classmethod
-    def execute(cls, answer=None):
+    def execute(cls, answer=None, is_api_call=False):
 
         # we keep looping over the LIFO til we have synapse list to process in it
         while cls.lifo_list:
@@ -52,8 +52,10 @@ class LIFOBuffer(object):
                     break
                 # get the first matched synapse in the list
                 matched_synapse = last_synapse_fifo_list[0]
-                # add the synapse to the API response so the user will get the status
-                cls.api_response.list_processed_matched_synapse.append(matched_synapse)
+                # add the synapse to the API response so the user will get the status if the synapse was not already
+                # in the response
+                if matched_synapse not in cls.api_response.list_processed_matched_synapse:
+                    cls.api_response.list_processed_matched_synapse.append(matched_synapse)
                 # while we have synapse to process in the list of synapse
                 while matched_synapse.neuron_fifo_list:
                     if cls.synapse_list_added_to_lifo:
@@ -67,11 +69,10 @@ class LIFOBuffer(object):
                         # the next neuron should not get this answer
                         answer = None
                     # todo fix this when we have a full client/server call. The client would be the voice or api call
-                    neuron.parameters["is_api_call"] = True
+                    neuron.parameters["is_api_call"] = is_api_call
                     # execute the neuron
-                    instantiated_neuron = NeuronLauncher.start_neuron_list_refacto(
-                        neuron=neuron,
-                        parameters_dict=matched_synapse.parameters)
+                    instantiated_neuron = NeuronLauncher.start_neuron(neuron=neuron,
+                                                                      parameters_dict=matched_synapse.parameters)
 
                     # by default, the status of an execution is "complete" if no neuron are waiting for an answer
                     cls.api_response.status = "complete"
@@ -107,4 +108,8 @@ class LIFOBuffer(object):
                 # remove the synapse list from the LIFO
                 cls.lifo_list.remove(last_synapse_fifo_list)
 
-        return cls.api_response.serialize()
+        # we prepare a json response
+        will_be_returned = cls.api_response.serialize()
+        # we clean up the API response object for the next call
+        cls.api_response = APIResponse()
+        return will_be_returned

+ 9 - 4
kalliope/core/Models/MatchedSynapse.py

@@ -16,11 +16,16 @@ class MatchedSynapse(object):
         """
         # create a copy of the synapse. the received synapse come from the brain.
         self.synapse = matched_synapse
-        # create a fifo list that contains all neurons to process
-        self.neuron_fifo_list = self.synapse.neurons
+        # create a fifo list that contains all neurons to process.
+        # Create a copy to be sure when we remove a neuron from this list it will not be removed from the synapse's
+        # neuron list
+        self.neuron_fifo_list = copy.deepcopy(self.synapse.neurons)
         self.matched_order = matched_order
-        self.parameters = NeuronParameterLoader.get_parameters(synapse_order=self.matched_order,
-                                                               user_order=user_order)
+        self.parameters = dict()
+        if matched_order is not None:
+            self.parameters = NeuronParameterLoader.get_parameters(synapse_order=self.matched_order,
+                                                                   user_order=user_order)
+
         # list of Neuron Module
         self.neuron_module_list = list()
 

+ 3 - 49
kalliope/core/NeuronLauncher.py

@@ -13,7 +13,7 @@ class NeuronLauncher:
         pass
 
     @classmethod
-    def start_neuron(cls, neuron):
+    def launch_neuron(cls, neuron):
         """
         Start a neuron plugin
         :param neuron: neuron object
@@ -33,53 +33,7 @@ class NeuronLauncher:
                                                      resources_dir=neuron_folder)
 
     @classmethod
-    def start_neuron_list(cls, neuron_list, parameters_dict=None):
-        """
-        Execute each neuron from the received neuron_list.
-        Replace parameter if exist 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: List of the instantiated neurons (no errors detected)
-        """
-
-        instantiated_neuron = list()
-
-        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:
-                instantiated_neuron.append(cls.start_neuron(neuron))
-            else:
-                Utils.print_danger("A problem has been found in the Synapse.")
-
-        return instantiated_neuron
-
-    @classmethod
-    def start_neuron_list_refacto(cls, neuron, parameters_dict=None):
+    def start_neuron(cls, neuron, parameters_dict=None):
         """
         Execute each neuron from the received neuron_list.
         Replace parameter if exist in the received dict of parameters_dict
@@ -115,7 +69,7 @@ class NeuronLauncher:
 
             # if no error detected, we run the neuron
             if not problem_in_neuron_found:
-                instantiated_neuron = cls.start_neuron(neuron)
+                instantiated_neuron = cls.launch_neuron(neuron)
             else:
                 Utils.print_danger("A problem has been found in the Synapse.")
 

+ 0 - 34
kalliope/core/NeuronModule.py

@@ -229,40 +229,6 @@ class NeuronModule(object):
         return OrderAnalyser().spelt_order_match_brain_order_via_table(order_to_analyse=order_match,
                                                                        user_said=order_said)
 
-    def run_synapse_by_name_with_order(self, order, synapse_name, order_template):
-        """
-        Run a synapse using its name, and giving an order so it can retrieve its params.
-        Useful for neurotransmitters.
-        :param order: the order to match
-        :param synapse_name: the name of the synapse
-        :param order_template: order_template coming from the neurotransmitter
-        :return: True if a synapse as been found and started using its params
-        """
-        synapse_to_run = self.brain.get_synapse_by_name(synapse_name=synapse_name)
-        if synapse_to_run:
-            # Make a list with the synapse
-            logger.debug("[run_synapse_by_name_with_order]-> a synapse has been found  %s" % synapse_to_run.name)
-            list_to_run = list()
-            list_to_run.append(synapse_to_run)
-
-            # load parameters from the answer
-            parameters = None
-            for signal in synapse_to_run.signals:
-                if isinstance(signal, Order):
-                    parameters = NeuronParameterLoader.get_parameters(synapse_order=order_template,
-                                                                      user_order=order)
-                    if parameters is not None:
-                        logger.debug("[NeuronModule]-> parameter load from user answer: %s" % parameters)
-                        break
-
-            # start the neuron list
-            NeuronLauncher.start_neuron_list(neuron_list=synapse_to_run.neurons, parameters_dict=parameters)
-
-        else:
-            logger.debug("[NeuronModule]-> run_synapse_by_name_with_order, the synapse has not been found : %s"
-                         % synapse_name)
-        return synapse_to_run
-
     @staticmethod
     def _get_content_of_file(real_file_template_path):
         """

+ 16 - 13
kalliope/core/RestAPI/FlaskAPI.py

@@ -45,8 +45,8 @@ class FlaskAPI(threading.Thread):
         sl = SettingLoader()
         self.settings = sl.settings
 
-        # list of launched synapse by the Order Analyser when using the /synapses/start/audio URL
-        self.launched_synapses = None
+        # api_response sent by the Order Analyser when using the /synapses/start/audio URL
+        self.api_response = None
         # boolean used to notify the main process that we get the list of returned synapse
         self.order_analyser_return = False
 
@@ -169,13 +169,13 @@ class FlaskAPI(threading.Thread):
             # get the order
             order_to_run = order["order"]
 
-            launched_synapses = SynapseLauncher.run_matching_synapse_or_default(order_to_run,
-                                                                                self.brain,
-                                                                                self.settings)
-
-            if launched_synapses:
+            api_response = SynapseLauncher.run_matching_synapse_from_order(order_to_run,
+                                                                           self.brain,
+                                                                           self.settings,
+                                                                           is_api_call=True)
+            if api_response:
                 # if the list is not empty, we have launched one or more synapses
-                data = jsonify(synapses=[e.serialize() for e in launched_synapses])
+                data = jsonify(api_response)
                 return data, 201
             else:
                 data = {
@@ -226,9 +226,9 @@ class FlaskAPI(threading.Thread):
             while not self.order_analyser_return:
                 time.sleep(0.1)
             self.order_analyser_return = False
-            if self.launched_synapses is not None and self.launched_synapses:
-                data = jsonify(synapses=[e.serialize() for e in self.launched_synapses])
-                self.launched_synapses = None
+            if self.api_response is not None and self.api_response:
+                data = jsonify(self.api_response)
+                self.api_response = None
                 return data, 201
             else:
                 data = {
@@ -256,8 +256,11 @@ class FlaskAPI(threading.Thread):
         :return:
         """
         logger.debug("order to process %s" % order)
-        list_launched_synapse = SynapseLauncher.run_matching_synapse_or_default(order, self.brain, self.settings)
-        self.launched_synapses = list_launched_synapse
+        api_response = SynapseLauncher.run_matching_synapse_from_order(order,
+                                                                       self.brain,
+                                                                       self.settings,
+                                                                       is_api_call=True)
+        self.api_response = api_response
 
         # this boolean will notify the main process that the order have been processed
         self.order_analyser_return = True

+ 22 - 55
kalliope/core/SynapseLauncher.py

@@ -1,5 +1,7 @@
 import logging
 
+from kalliope.core.ConfigurationManager import BrainLoader
+
 from kalliope.core.Models.LIFOBuffer import LIFOBuffer
 from kalliope.core.Models.MatchedSynapse import MatchedSynapse
 from kalliope.core.NeuronLauncher import NeuronLauncher
@@ -54,53 +56,6 @@ class SynapseLauncher(object):
             synapse.answers.append(instantiated_neuron.tts_message)
         return synapse
 
-    @classmethod
-    def run_matching_synapse_or_default(cls, order_to_process, brain, settings):
-        """
-        This method will run all synapse that match the given order "order_to_process"
-        :param order_to_process: The text order to process in the order analyser
-        :param brain: Brain instance
-        :param settings: Settings instance
-        :return: Return a list of launched synapse
-        """
-        no_synapse_match = False
-        # create a list of launched synapse to return
-        launched_synapses = list()
-        if order_to_process is not None:  # maybe we have received a null audio from STT engine
-            launched_synapses_tuple = OrderAnalyser.get_matching_synapse(order=order_to_process, brain=brain)
-
-            # oa contains the list Named tuple of synapse to run with the associated order that has matched
-            # for each synapse, get neurons, et for each neuron, get parameters
-            if not launched_synapses_tuple:
-                no_synapse_match = True
-            else:
-                # the order match one or more synapses
-                for tuple_el in launched_synapses_tuple:
-
-                    logger.debug("[SynapseLauncher] Get parameter for %s " % tuple_el.synapse.name)
-                    parameters = NeuronParameterLoader.get_parameters(synapse_order=tuple_el.order,
-                                                                      user_order=order_to_process)
-                    # start the neuron list
-                    instantiated_neuron_list = NeuronLauncher.start_neuron_list(neuron_list=tuple_el.synapse.neurons,
-                                                                                parameters_dict=parameters)
-                    # add generated tts messages to the returned synapse
-                    for neuron in instantiated_neuron_list:
-                        tuple_el.synapse.answers.append(neuron.tts_message)
-
-                    launched_synapses.append(tuple_el.synapse)
-        else:
-            no_synapse_match = True
-
-        if no_synapse_match:  # then run the default synapse
-            if settings.default_synapse is not None:
-                logger.debug("[SynapseLauncher] No matching Synapse-> running default synapse ")
-                synapses = SynapseLauncher.start_synapse(name=settings.default_synapse,
-                                                         brain=brain)
-                launched_synapses.append(synapses)
-
-        # return the launched synapse list
-        return launched_synapses
-
     @classmethod
     def run_matching_synapse_from_order(cls, order_to_process, brain, settings, is_api_call=False):
         """
@@ -118,7 +73,7 @@ class SynapseLauncher(object):
         # if the LIFO is not empty, so, the current order is passed to the current processing synapse as an answer
         if len(lifo_buffer.lifo_list) > 0:
             # the LIFO is not empty, this is an answer to a previous call
-            return lifo_buffer.execute(answer=order_to_process)
+            return lifo_buffer.execute(answer=order_to_process, is_api_call=is_api_call)
 
         else:
             # the LIFO is empty, this is a new call
@@ -128,14 +83,26 @@ class SynapseLauncher(object):
 
             # we transform the tuple in a MatchedSynapse list
             list_synapse_to_process = list()
-            for tuple_el in synapses_to_launch_tuple:
-                new_matching_synapse = MatchedSynapse(matched_synapse=tuple_el.synapse,
-                                                      matched_order=tuple_el.order,
-                                                      user_order=order_to_process)
-                list_synapse_to_process.append(new_matching_synapse)
+
+            if synapses_to_launch_tuple:  # the order analyser returned us a list
+                for tuple_el in synapses_to_launch_tuple:
+                    new_matching_synapse = MatchedSynapse(matched_synapse=tuple_el.synapse,
+                                                          matched_order=tuple_el.order,
+                                                          user_order=order_to_process)
+                    list_synapse_to_process.append(new_matching_synapse)
+            else:
+                # execute the default synapse if exist
+                if settings.default_synapse:
+                    logger.debug("[SynapseLauncher] No matching Synapse-> running default synapse ")
+                    # get the default synapse
+                    default_synapse = BrainLoader().get_brain().get_synapse_by_name(settings.default_synapse)
+
+                    new_matching_synapse = MatchedSynapse(matched_synapse=default_synapse,
+                                                          matched_order=None,
+                                                          user_order=order_to_process)
+                    list_synapse_to_process.append(new_matching_synapse)
 
             lifo_buffer.add_synapse_list_to_lifo(list_synapse_to_process)
 
             lifo_buffer.api_response.user_order = order_to_process
-            return lifo_buffer.execute()
-
+            return lifo_buffer.execute(is_api_call=is_api_call)

+ 0 - 3
kalliope/neurons/neurotransmitter/neurotransmitter.py

@@ -50,9 +50,6 @@ class Neurotransmitter(NeuronModule):
                     if self.is_order_matching(audio, answer):
                         logger.debug("Neurotransmitter: match answer: %s" % answer)
                         self.run_synapse_by_name(synapse_name=el["synapse"], user_order=audio, synapse_order=answer)
-                        # found = self.run_synapse_by_name_with_order(order=audio,
-                        #                                             synapse_name=el["synapse"],
-                        #                                             order_template=answer)
                         found = True
                         break
             if not found:  # the answer do not correspond to any answer. We run the default synapse