Browse Source

link new OA with main controller and API

nico 8 năm trước cách đây
mục cha
commit
4954910b6e

+ 109 - 0
Tests/test_order_analyser2.py

@@ -0,0 +1,109 @@
+import unittest
+
+import logging
+
+from kalliope.core.Models import Brain
+from kalliope.core.Models import Neuron
+from kalliope.core.Models import Order
+from kalliope.core.Models import Synapse
+from kalliope.core.Models.Settings import Settings
+from kalliope.core.OrderAnalyser2 import OrderAnalyser2
+
+
+logging.basicConfig()
+logger = logging.getLogger("kalliope")
+logger.setLevel(logging.DEBUG)
+
+
+class TestOrderAnalyser2(unittest.TestCase):
+
+    """Test case for the OrderAnalyser Class"""
+
+    def setUp(self):
+        pass
+
+    def test_get_matching_synapse(self):
+        # Init
+        neuron1 = Neuron(name='neurone1', parameters={'var1': 'val1'})
+        neuron2 = Neuron(name='neurone2', parameters={'var2': 'val2'})
+        neuron3 = Neuron(name='neurone3', parameters={'var3': 'val3'})
+        neuron4 = Neuron(name='neurone4', parameters={'var4': 'val4'})
+
+        signal1 = Order(sentence="this is the sentence")
+        signal2 = Order(sentence="this is the second sentence")
+        signal3 = Order(sentence="that is part of the third sentence")
+
+        synapse1 = Synapse(name="Synapse1", neurons=[neuron1, neuron2], signals=[signal1])
+        synapse2 = Synapse(name="Synapse2", neurons=[neuron3, neuron4], signals=[signal2])
+        synapse3 = Synapse(name="Synapse3", neurons=[neuron2, neuron4], signals=[signal3])
+
+        all_synapse_list = [synapse1,
+                            synapse2,
+                            synapse3]
+
+        br = Brain(synapses=all_synapse_list)
+
+        # TEST1: should return synapse1
+        spoken_order = "this is the sentence"
+        matched_synapses = OrderAnalyser2.get_matching_synapse(order=spoken_order, brain=br)
+        self.assertEqual(len(matched_synapses), 1)
+
+        # TEST2: should empty
+        spoken_order = "not a valid order"
+        matched_synapses = OrderAnalyser2.get_matching_synapse(order=spoken_order, brain=br)
+        self.assertFalse(matched_synapses)
+
+    def test_spelt_order_match_brain_order_via_table(self):
+        order_to_test = "this is the order"
+        sentence_to_test = "this is the order"
+
+        # Success
+        self.assertTrue(OrderAnalyser2.spelt_order_match_brain_order_via_table(order_to_test, sentence_to_test))
+
+        # Failure
+        sentence_to_test = "unexpected sentence"
+        self.assertFalse(OrderAnalyser2.spelt_order_match_brain_order_via_table(order_to_test, sentence_to_test))
+
+        # Upper/lower cases
+        sentence_to_test = "THIS is THE order"
+        self.assertTrue(OrderAnalyser2.spelt_order_match_brain_order_via_table(order_to_test, sentence_to_test))
+
+    def test_get_split_order_without_bracket(self):
+        # Success
+        order_to_test = "this is the order"
+        expected_result = ["this", "is", "the", "order"]
+        self.assertEqual(OrderAnalyser2._get_split_order_without_bracket(order_to_test), expected_result,
+                         "No brackets Fails to return the expected list")
+
+        order_to_test = "this is the {{ order }}"
+        expected_result = ["this", "is", "the"]
+        self.assertEqual(OrderAnalyser2._get_split_order_without_bracket(order_to_test), expected_result,
+                         "With spaced brackets Fails to return the expected list")
+
+        order_to_test = "this is the {{order }}"    # left bracket without space
+        expected_result = ["this", "is", "the"]
+        self.assertEqual(OrderAnalyser2._get_split_order_without_bracket(order_to_test), expected_result,
+                         "Left brackets Fails to return the expected list")
+
+        order_to_test = "this is the {{ order}}"    # right bracket without space
+        expected_result = ["this", "is", "the"]
+        self.assertEqual(OrderAnalyser2._get_split_order_without_bracket(order_to_test), expected_result,
+                         "Right brackets Fails to return the expected list")
+
+        order_to_test = "this is the {{order}}"  # bracket without space
+        expected_result = ["this", "is", "the"]
+        self.assertEqual(OrderAnalyser2._get_split_order_without_bracket(order_to_test), expected_result,
+                         "No space brackets Fails to return the expected list")
+
+    def test_counter_subset(self):
+        list1 = ("word1", "word2")
+        list2 = ("word3", "word4")
+        list3 = ("word1", "word2", "word3", "word4")
+
+        self.assertFalse(OrderAnalyser2._counter_subset(list1, list2))
+        self.assertTrue(OrderAnalyser2._counter_subset(list1, list3))
+        self.assertTrue(OrderAnalyser2._counter_subset(list2, list3))
+
+
+if __name__ == '__main__':
+    unittest.main()

+ 25 - 3
kalliope/core/MainController.py

@@ -3,6 +3,10 @@ import random
 from time import sleep
 
 from flask import Flask
+
+from kalliope.core.NeuronLauncher import NeuronLauncher
+from kalliope.core.NeuronParameterLoader import NeuronParameterLoader
+from kalliope.core.OrderAnalyser2 import OrderAnalyser2
 from kalliope.core.SynapseLauncher import SynapseLauncher
 from transitions import Machine
 
@@ -108,7 +112,7 @@ class MainController:
         """
         logger.debug("Entering state: %s" % self.state)
         if (not self.on_ready_notification_played_once and self.settings.play_on_ready_notification == "once") or \
-                self.settings.play_on_ready_notification == "always":
+                        self.settings.play_on_ready_notification == "always":
             # we remember that we played the notification one time
             self.on_ready_notification_played_once = True
             # here we tell the user that we are listening
@@ -192,12 +196,30 @@ class MainController:
         Start the order analyser with the caught order to process
         """
         logger.debug("order in analysing_order_thread %s" % self.order_to_process)
+        no_synapse_match = False
         if self.order_to_process is not None:   # maybe we have received a null audio from STT engine
-            order_analyser = OrderAnalyser(self.order_to_process, brain=self.brain)
-            order_analyser.start()
+            oa2 = OrderAnalyser2.get_matching_synapse(order=self.order_to_process, brain=self.brain)
+
+            # oa2 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 oa2:
+                no_synapse_match = True
+            else:
+                # the order match one or more synapses
+                for tuple_el in oa2:
+                    logger.debug("Get parameter for %s " % tuple_el.synapse.name)
+                    parameters = NeuronParameterLoader.get_parameters(synapse_order=tuple_el.order,
+                                                                      user_order=self.order_to_process).next()
+                    # start the neuron list
+                    NeuronLauncher.start_neuron_list(neuron_list=tuple_el.synapse.neurons,
+                                                     parameters_dict=parameters)
         else:
+            no_synapse_match = True
+
+        if no_synapse_match:  # then run the default synapse
             if self.settings.default_synapse is not None:
                 SynapseLauncher.start_synapse(name=self.settings.default_synapse, brain=self.brain)
+
         # return to the state "unpausing_trigger"
         self.unpause_trigger()
 

+ 7 - 3
kalliope/core/NeuronLauncher.py

@@ -33,7 +33,7 @@ class NeuronLauncher:
                                                      resources_dir=neuron_folder)
 
     @classmethod
-    def start_neuron_list(cls, neuron_list, parameters_dict):
+    def start_neuron_list(cls, neuron_list, parameters_dict=None):
         """
         Execute each neuron from the received neuron_list.
         Replace parameter if existe in the received dict of parameters_dict
@@ -41,8 +41,10 @@ class NeuronLauncher:
         :param parameters_dict: dict of parameter to load in each neuron if expecting a parameter
         :return:
         """
-        for neuron in neuron_list:
 
+        instantiated_neuron = list()
+
+        for neuron in neuron_list:
             problem_in_neuron_found = False
             if isinstance(neuron.parameters, dict):
                 # print neuron.parameters
@@ -70,6 +72,8 @@ class NeuronLauncher:
 
             # if no error detected, we run the neuron
             if not problem_in_neuron_found:
-                cls.start_neuron(neuron)
+                instantiated_neuron.append(cls.start_neuron(neuron))
             else:
                 Utils.print_danger("A problem has been found in the Synapse.")
+
+        return instantiated_neuron

+ 3 - 4
kalliope/core/NeuronModule.py

@@ -1,19 +1,18 @@
 # coding: utf8
 import logging
 import random
-
 import sys
+
 from jinja2 import Template
 
-from kalliope.OrderAnalyser2 import OrderAnalyser2
 from kalliope.core import OrderListener
-from kalliope.core import OrderAnalyser
+from kalliope.core.ConfigurationManager import SettingLoader, BrainLoader
 from kalliope.core.Models import Order
 from kalliope.core.NeuronLauncher import NeuronLauncher
 from kalliope.core.NeuronParameterLoader import NeuronParameterLoader
+from kalliope.core.OrderAnalyser2 import OrderAnalyser2
 from kalliope.core.SynapseLauncher import SynapseLauncher
 from kalliope.core.Utils.Utils import Utils
-from kalliope.core.ConfigurationManager import SettingLoader, BrainLoader
 
 logging.basicConfig()
 logger = logging.getLogger("kalliope")

+ 9 - 7
kalliope/OrderAnalyser2.py → kalliope/core/OrderAnalyser2.py

@@ -31,6 +31,12 @@ class OrderAnalyser2:
         if isinstance(order, str):
             order = order.decode('utf-8')
 
+        # We use a namedtuple to associate the synapse and the signal of the synapse
+        synapse_order_tuple = collections.namedtuple('tuple_synapse_matchingOrder',
+                                                     ['synapse', 'order'])
+
+        list_match_synapse = list()
+
         # test each synapse from the brain
         for synapse in cls.brain.synapses:
             # we are only concerned by synapse with a order type of signal
@@ -38,14 +44,10 @@ class OrderAnalyser2:
                 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)
+                        logger.debug("Order found! Run synapse name: %s" % synapse.name)
                         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)
+                        list_match_synapse.append(synapse_order_tuple(synapse=synapse, order=signal.sentence))
+        return list_match_synapse
 
     @classmethod
     def spelt_order_match_brain_order_via_table(cls, order_to_analyse, user_said):

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

@@ -4,6 +4,9 @@ import threading
 
 import time
 
+from kalliope.core.NeuronLauncher import NeuronLauncher
+from kalliope.core.NeuronParameterLoader import NeuronParameterLoader
+from kalliope.core.OrderAnalyser2 import OrderAnalyser2
 from kalliope.core.Utils.FileManager import FileManager
 
 from kalliope.core.ConfigurationManager import SettingLoader
@@ -256,8 +259,19 @@ class FlaskAPI(threading.Thread):
         """
         logger.debug("order to process %s" % order)
         if order is not None:  # maybe we have received a null audio from STT engine
-            order_analyser = OrderAnalyser(order, brain=self.brain)
-            synapses_launched = order_analyser.start()
+            synapses_launched = list()
+
+            oa2 = OrderAnalyser2.get_matching_synapse(order=order, brain=self.brain)
+
+            # oa2 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
+            for tuple_el in oa2:
+                logger.debug("Get parameter for %s " % tuple_el.synapse.name)
+                parameters = NeuronParameterLoader.get_parameters(synapse_order=tuple_el.order,
+                                                                  user_order=order).next()
+                # start the neuron list
+                synapses_launched = NeuronLauncher.start_neuron_list(neuron_list=tuple_el.synapse.neurons,
+                                                                     parameters_dict=parameters)
             self.launched_synapses = synapses_launched
         else:
             if self.settings.default_synapse is not None: