OrderAnalyser.py 8.5 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190
  1. # coding: utf8
  2. import re
  3. from core.Utils import Utils
  4. from core.ConfigurationManager.BrainLoader import BrainLoader
  5. from core.Models import Order
  6. from core.NeuroneLauncher import NeuroneLauncher
  7. from Cosine import *
  8. import logging
  9. logging.basicConfig()
  10. logger = logging.getLogger("jarvis")
  11. class OrderAnalyser:
  12. def __init__(self, order, main_controller=None, brain_file=None):
  13. """
  14. Class used to load brain and run neuron attached to the received order
  15. :param order: spelt order
  16. :param main_controller
  17. :param brain_file: To override the default brain.yml file
  18. """
  19. self.main_controller = main_controller
  20. self.order = order
  21. if brain_file is None:
  22. self.brain = BrainLoader.get_brain()
  23. else:
  24. self.brain = BrainLoader.get_brain(file_path=brain_file)
  25. logger.debug("OrderAnalyser, Received order: %s" % self.order)
  26. def start(self):
  27. synapses_found = False
  28. for synapse in self.brain.synapses:
  29. for signal in synapse.signals:
  30. if type(signal) == Order:
  31. if self._spelt_order_match_brain_order_via_table(signal.sentence, self.order):
  32. synapses_found = True
  33. logger.debug("Order found! Run neurons: %s" % synapse.neurons)
  34. Utils.print_success("Order matched in the brain. Running synapse \"%s\"" % synapse.name)
  35. # if the order contains bracket, we get parameters said by the user
  36. params = None
  37. if self._is_containing_bracket(signal.sentence):
  38. params = self._associate_order_params_to_values(signal.sentence)
  39. logger.debug("Parameters for order: %s" % params)
  40. for neuron in synapse.neurons:
  41. if isinstance(neuron.parameters, dict):
  42. if "args" in neuron.parameters:
  43. logger.debug("The neuron wait for parameter")
  44. # check that the user added parameters to his order
  45. if params is None:
  46. # TODO: raise an error and break the program?
  47. Utils.print_danger("Error: The neuron %s is waiting for argument. "
  48. "Argument found in bracket in the given order" % neuron.name)
  49. else:
  50. # we add wanted arguments the existing neuron parameter dict
  51. for arg in neuron.parameters["args"]:
  52. if arg in params:
  53. logger.debug("Parameter %s added to the current parameter "
  54. "of the neuron: %s" % (arg, neuron.name))
  55. neuron.parameters[arg] = params[arg]
  56. print params[arg]
  57. else:
  58. # TODO: raise an error and break the program?
  59. Utils.print_danger("Error: Argument \"%s\" not found in the"
  60. " order" % arg)
  61. # neuron.parameters = dict(neuron.parameters.items() + params.items())
  62. print neuron.parameters
  63. NeuroneLauncher.start_neurone(neuron)
  64. if not synapses_found:
  65. Utils.print_info("No synapse match the captured order: %s" % self.order)
  66. def _spelt_order_match_brain_order(self, order_to_test):
  67. """
  68. test if the current order match the order spelt by the user
  69. :param order_to_test:
  70. :return:
  71. """
  72. # TODO : In "order_to_test" should we remove double brace and variable name before checking to optimise the cosine ?
  73. user_vector = text_to_vector(self.order)
  74. order_vector = text_to_vector(order_to_test)
  75. cosine = get_cosine(user_vector, order_vector)
  76. logger.debug("the cosine : %s, pour user_vector: %s , order_vector: %s" % (cosine, self.order, order_to_test))
  77. return cosine >= 0.9
  78. def _associate_order_params_to_values(self, order_to_check):
  79. """
  80. Associate the variables from the order to the incoming user order
  81. :param order: the order to check
  82. :return: the dict corresponding to the key / value of the params
  83. """
  84. # Remove white spaces (if any) between the variable and the double brace then split
  85. list_word_in_order = re.sub('\s+(?=[^\{\{\}\}]*\}\})', '', order_to_check).split()
  86. # get the order, defined by the first words before {{
  87. # /!\ Could be empty if order starts with double brace
  88. the_order = order_to_check[:order_to_check.find('{{')]
  89. # remove sentence before order which are sentences not matching anyway
  90. truncate_user_sentence = self.order[self.order.find(the_order):]
  91. truncate_list_word_said = truncate_user_sentence.split()
  92. # make dict var:value
  93. dictVar = {}
  94. for idx, ow in enumerate(list_word_in_order):
  95. if self._is_containing_bracket(ow):
  96. # remove bracket and grab the next value / stop value
  97. varname = ow.replace("{{", "").replace("}}", "")
  98. stopValue = self._get_next_value_list(list_word_in_order[idx:])
  99. if stopValue is None:
  100. dictVar[varname] = " ".join(truncate_list_word_said)
  101. break
  102. for word_said in truncate_list_word_said:
  103. if word_said == stopValue: break
  104. if varname in dictVar:
  105. dictVar[varname] += " " + word_said
  106. truncate_list_word_said = truncate_list_word_said[1:]
  107. else:
  108. dictVar[varname] = word_said
  109. truncate_list_word_said = truncate_list_word_said[1:]
  110. return dictVar
  111. @staticmethod
  112. def _is_containing_bracket(sentence):
  113. # print "sentence to test %s" % sentence
  114. pattern = r"{{|}}"
  115. # prog = re.compile(pattern)
  116. bool = re.search(pattern, sentence)
  117. if bool is not None:
  118. return True
  119. return False
  120. @staticmethod
  121. def _get_next_value_list(list):
  122. ite = list.__iter__()
  123. next(ite, None)
  124. return next(ite, None)
  125. def _spelt_order_match_brain_order_via_table(self, order_to_analyse, user_said):
  126. """
  127. return true if all string that are in the sentence are present in the order to test
  128. :param order_to_analyse: String order to test
  129. :param user_said: String to compare to the order
  130. :return: True if all string are present in the order
  131. """
  132. list_word_user_said = user_said.split()
  133. split_order_without_bracket = self._get_split_order_without_bracket(order_to_analyse)
  134. print split_order_without_bracket
  135. number_of_word_in_order = len(split_order_without_bracket)
  136. # if all words in the list of what the user said in in the list of word in the order
  137. # return len(set(split_order_without_bracket).intersection(list_word_user_said)) == number_of_word_in_order
  138. return self._counterSubset(split_order_without_bracket, list_word_user_said)
  139. @staticmethod
  140. def _get_split_order_without_bracket(order):
  141. """
  142. Get an order with bracket inside like: "hello my name is {{ name }}.
  143. return a list of string without bracket like ["hello", "my", "name", "is"]
  144. :param order: sentence to split
  145. :return: list of string without bracket
  146. """
  147. pattern = r"((?:{{\s*)[\w\.]+(?:\s*}}))"
  148. # find everything like {{ word }}
  149. matches = re.findall(pattern, order)
  150. for match in matches:
  151. order = order.replace(match, "")
  152. # then split
  153. split_order = order.split()
  154. return split_order
  155. @staticmethod
  156. def _counterSubset(list1, list2):
  157. """
  158. check if the number of occurrences matches
  159. :param list1:
  160. :param list2:
  161. :return:
  162. """
  163. c1, c2 = Counter(list1), Counter(list2)
  164. for k, n in c1.items():
  165. if n > c2[k]:
  166. return False
  167. return True