Преглед изворни кода

[Feature] Cosine Similarity + associate order param

monf пре 8 година
родитељ
комит
abdd8e3c83
7 измењених фајлова са 243 додато и 19 уклоњено
  1. 3 3
      brain.yml
  2. 24 0
      core/Cosine.py
  3. 2 1
      core/NeuroneLauncher.py
  4. 66 3
      core/OrderAnalyser.py
  5. 4 1
      neurons/systemdate/systemdate.py
  6. 23 11
      test.py
  7. 121 0
      test_Order_param.py

+ 3 - 3
brain.yml

@@ -6,7 +6,7 @@
             - "Hello, I'm Jarvis"
     signals:
       - order: "hello"
-      - order: "je voudrais ecouter {{ artist_name }}"
+      - order: "je voudrais la musique {{song-name}} de {{ artist_name }}"
 
   - name: "say hello"
     neurons:
@@ -39,11 +39,11 @@
     neurons:
       - systemdate:
           say_template:
-            - "Il est {{ hours }} heures et {{ minutes }} minutes"
+            - "Il est {{ hours }} heures et {{ minutes }} minutes {{insulte}}"
           tts: "voxygen"
           cache: False
     signals:
-      - order: "what time"
+      - order: "{{politesse}} quelle heure est-il {{insulte}}"
 
   - name: "Say local date from template"
     neurons:

+ 24 - 0
core/Cosine.py

@@ -0,0 +1,24 @@
+import re, math
+from collections import Counter
+
+def get_cosine(vec1, vec2):
+    """"
+    :return the cosine of 2 vectors following the math equation from Wikipedia
+    """
+    intersection = set(vec1.keys()) & set(vec2.keys())
+    numerator = sum([vec1[x] * vec2[x] for x in intersection])
+
+    sum1 = sum([vec1[x] ** 2 for x in vec1.keys()])
+    sum2 = sum([vec2[x] ** 2 for x in vec2.keys()])
+    denominator = math.sqrt(sum1) * math.sqrt(sum2)
+
+    if not denominator:
+        return 0.0
+    else:
+        return float(numerator) / denominator
+
+
+def text_to_vector(text):
+    WORD = re.compile(r'\w+')
+    words = WORD.findall(text)
+    return Counter(words)

+ 2 - 1
core/NeuroneLauncher.py

@@ -16,13 +16,14 @@ class NeuroneLauncher:
         pass
 
     @classmethod
-    def start_neurone(cls, neuron):
+    def start_neurone(cls, neuron, params):
         """
         Start a neuron plugin
         :param neuron: neuron object
         :type neuron: Neurone
         :return:
         """
+        neuron.parameters = dict(neuron.parameters.items() + params.items())
         logger.debug("Run plugin \"%s\" with parameters %s" % (neuron.name, neuron.parameters))
         return Utils.get_dynamic_class_instantiation("neurons", neuron.name.capitalize(), neuron.parameters)
 

+ 66 - 3
core/OrderAnalyser.py

@@ -4,6 +4,8 @@ from core.Utils import Utils
 from core.ConfigurationManager.BrainLoader import BrainLoader
 from core.Models import Order
 from core.NeuroneLauncher import NeuroneLauncher
+from Cosine import *
+
 import logging
 
 logging.basicConfig()
@@ -35,22 +37,83 @@ class OrderAnalyser:
                         synapses_found = True
                         logger.debug("Order found! Run neurons: %s" % synapse.neurons)
                         Utils.print_success("Order matched in the brain. Running synapse \"%s\"" % synapse.name)
+                        params = {}
+                        if self._is_containing_bracket(signal.sentence):
+                            params = self._associate_order_params_to_values(signal.sentence)
                         for neuron in synapse.neurons:
-                            NeuroneLauncher.start_neurone(neuron)
+                            NeuroneLauncher.start_neurone(neuron, params)
 
         if not synapses_found:
             Utils.print_info("No synapse match the captured order: %s" % self.order)
 
     def _spelt_order_match_brain_order(self, order_to_test):
         """
+
         test if the current order match the order spelt by the user
         :param order_to_test:
         :return:
         """
-        my_regex = r"\b(?=\w)" + re.escape(order_to_test) + r"\b(?!\w)"
+        # TODO : In "order_to_test" should we remove double brace and variable name before checking to optimise the cosine ?
+        user_vector = text_to_vector(self.order)
+        order_vector = text_to_vector(order_to_test)
+
+        cosine = get_cosine(user_vector, order_vector)
+        print "the cosine : ", cosine, ", pour user_vector: ", self.order, " et order_vector: ", order_to_test
+        return cosine >= 0.5
+
+
+    def _associate_order_params_to_values(self, order_to_check):
+        """
+        Associate the variables from the order to the incoming user order
+        :param order: the order to check
+        :return: the dict corresponding to the key / value of the params
+        """
+
+        # Remove white spaces (if any) between the variable and the double brace then split
+        list_word_in_order = re.sub('\s+(?=[^\{\{\}\}]*\}\})', '', 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
+        truncate_user_sentence = self.order[self.order.find(the_order):]
+        truncate_list_word_said = truncate_user_sentence.split()
+
+        # make dict var:value
+        dictVar = {}
+        for idx, ow in enumerate(list_word_in_order):
+            if self._is_containing_bracket(ow):
+                # remove bracket and grab the next value / stop value
+                varname = ow.replace("{{", "").replace("}}", "")
+                stopValue = self._get_next_value_list(list_word_in_order[idx:])
+                if stopValue is None:
+                    dictVar[varname] = " ".join(truncate_list_word_said)
+                    break
+                for word_said in truncate_list_word_said:
+                    if word_said == stopValue: break
+                    if varname in dictVar:
+                        dictVar[varname] += " " + word_said
+                        truncate_list_word_said = truncate_list_word_said[1:]
+                    else:
+                        dictVar[varname] = word_said
+            truncate_list_word_said = truncate_list_word_said[1:]
+        return dictVar
+
 
-        if re.search(my_regex, self.order, re.IGNORECASE):
+    @staticmethod
+    def _is_containing_bracket(sentence):
+        # print "sentence to test %s" % sentence
+        pattern = r"{{|}}"
+        # prog = re.compile(pattern)
+        bool = re.search(pattern, sentence)
+        if bool is not None:
             return True
         return False
 
+    @staticmethod
+    def _get_next_value_list(list):
+        ite = list.__iter__()
+        next(ite, None)
+        return next(ite, None)
 

+ 4 - 1
neurons/systemdate/systemdate.py

@@ -13,8 +13,11 @@ class Systemdate(NeuronModule):
         hour = time.strftime("%H")
         minute = time.strftime("%M")
 
+
         message = {
             "hours": hour,
-            "minutes": minute
+            "minutes": minute,
         }
+        if "insulte" in kwargs:
+            message["insulte"] = kwargs.get("insulte")
         self.say(message)

+ 23 - 11
test.py

@@ -9,11 +9,21 @@ from collections import Counter
 # order = "je voudrais ecouter {{ artist_name }}"
 
 user_said = "s'il te plait regle le reveil pour dix huit heures et dix neuf  minutes trente trois  secondes cent quatre vingt dix "
-user_said2 = "s'il te pingt dix "
-user_said3 = "s'il te plait regle le reveil pour dix huit huf  minutes trente trois  secondes cent quatre vingt dix "
-user_said4 = "s'il te plait regle lpour dix huit heures et dix neuf  minutes trente trois  secondes cent quatre vingt dix "
-user_said5 = "s'il te plait regle le reveil poutes trente trois  secondes cent quatre vingt dix "
-order = "regle le reveil pour {{ hour}} heures et {{minute }} minutes {{ seconde  }} secondes {{mili}}"
+
+user_said_list = [" regle le reveil pour neuf  heures et quinze minutes trente trois secondes ",
+                 "s'il te plait regle le reveil pour dix huit huf  minutes trente trois  secondes cent quatre vingt dix ",
+                 "regle pour dix huit heures et   trente trois  secondes cent quatre vingt dix ",
+                 "s'il te plait regle le reveil poutes trente trois  secondes cent quatre vingt dix ",
+                 "RIEN A VOIR"
+                  ]
+
+order = "{{ politesse }} regle le reveil pour {{ hour}} heures et {{minute }} minutes {{ seconde  }} secondes {{mili}}"
+
+order_list = ["regle le reveil pour  heures et  minutes  secondes ",
+              "{{ politesse }} regle le reveil pour {{ hour}} heures et {{minute }} minutes {{ seconde  }} secondes {{mili}}",
+              " reveil pour {{ hour}}  et {{minute }} minutes  secondes {{mili}}",
+              "{{ politesse }} regle le reveil pour "
+              ]
 
 
 # take a look to each order
@@ -93,12 +103,14 @@ if _is_containing_bracket(order):
 
 
 
-vector1 = text_to_vector(user_said)
-vector2 = text_to_vector(order)
-
-cosine = get_cosine(vector1, vector2)
-
-print 'Cosine:', cosine
+# for us in user_said_list:
+#     for od in order_list:
+#         vector1 = text_to_vector(us)
+#         vector2 = text_to_vector(od)
+#
+#         cosine = get_cosine(vector1, vector2)
+#
+#         print "Cosine -> ", cosine, " for usersaid: ",us, " ,order:", od
 
 
 

+ 121 - 0
test_Order_param.py

@@ -0,0 +1,121 @@
+# -*- coding: utf-8 -*-
+
+import re, math
+from collections import Counter
+
+
+
+# user_said = "maman je voudrais ecouter ACDC"
+# order = "je voudrais ecouter {{ artist_name }}"
+
+user_said = "s'il te plait regle le reveil pour dix huit heures et dix neuf  minutes trente trois  secondes cent quatre vingt dix "
+
+user_said_list = [" regle le reveil pour neuf  heures et quinze minutes trente trois secondes ",
+                 "s'il te plait regle le reveil pour dix huit huf  minutes trente trois  secondes cent quatre vingt dix ",
+                 "regle pour dix huit heures et   trente trois  secondes cent quatre vingt dix ",
+                 "s'il te plait regle le reveil poutes trente trois  secondes cent quatre vingt dix ",
+                 "RIEN A VOIR",
+                " minutes neuf trente reveil regle secondes  quinze  le heures et    trois  pour "
+                  ]
+
+order = "{{ politesse }} regle le reveil pour {{ hour}} heures et {{minute }} minutes {{ seconde  }} secondes {{mili}}"
+
+order_list = ["regle le reveil pour  heures et  minutes  secondes ",
+              "{{ politesse }} regle le reveil pour {{ hour}} heures et {{minute }} minutes {{ seconde  }} secondes {{mili}}",
+              "politesse  regle le reveil pour  hour heures et minute  minutes  seconde   secondes mili",
+              " reveil pour {{ hour}}  et {{minute }} minutes  secondes {{mili}}",
+              "{{ politesse }} regle le reveil pour "
+              ]
+
+
+# take a look to each order
+
+WORD = re.compile(r'\w+')
+
+def get_cosine(vec1, vec2):
+     intersection = set(vec1.keys()) & set(vec2.keys())
+     numerator = sum([vec1[x] * vec2[x] for x in intersection])
+
+     sum1 = sum([vec1[x]**2 for x in vec1.keys()])
+     sum2 = sum([vec2[x]**2 for x in vec2.keys()])
+     denominator = math.sqrt(sum1) * math.sqrt(sum2)
+
+     if not denominator:
+        return 0.0
+     else:
+        return float(numerator) / denominator
+
+def text_to_vector(text):
+     words = WORD.findall(text)
+     return Counter(words)
+
+
+def _is_containing_bracket(sentence):
+    # print "sentence to test %s" % sentence
+    pattern = r"{{|}}"
+    # prog = re.compile(pattern)
+    bool = re.search(pattern, sentence)
+    if bool is not None:
+        return True
+    return False
+
+
+def _get_next_value_list(list):
+    ite = list.__iter__()
+    next(ite, None)
+    return next(ite, None)
+
+# check if the order contain bracket
+if _is_containing_bracket(order):
+    # remove white space between {{ and }}
+    # get a table of word said
+    list_word_in_order = re.sub('\s+(?=[^\{\{\}\}]*\}\})', '',order).split()
+    print "order matched: %s" % list_word_in_order
+
+    # get the order, defined by the first words before {{
+    the_order = order[:order.find('{{')]
+    print "the order catched %s" % the_order
+
+
+    # remove sentence before order
+    nb = user_said[user_said.find(the_order):]
+    truncate_list_word_said = nb.split()
+    print "truncate_list_word_said : %s" % truncate_list_word_said
+
+
+    # make dict var:value
+    dictVar = {}
+    for idx, ow in enumerate(list_word_in_order):
+        if _is_containing_bracket(ow):
+            # remove bracket et key dict
+            varname = ow.replace("{{","").replace("}}", "")
+            stopValue = _get_next_value_list(list_word_in_order[idx:])
+            if stopValue is None:
+                dictVar[varname] = " ".join(truncate_list_word_said)
+                break
+            for word_said in truncate_list_word_said:
+                if word_said == stopValue: break
+                if varname in dictVar:
+                    dictVar[varname] += " " + word_said
+                    truncate_list_word_said = truncate_list_word_said[1:]
+                else:
+                    dictVar[varname] = word_said
+        truncate_list_word_said = truncate_list_word_said[1:]
+    print "The dict Var : %s" % dictVar
+
+
+
+for us in user_said_list:
+    for od in order_list:
+        vector1 = text_to_vector(us)
+        vector2 = text_to_vector(od)
+
+        cosine = get_cosine(vector1, vector2)
+
+        print "Cosine -> ", cosine, " for usersaid: ",us, " ,order:", od
+
+
+
+
+
+