OrderAnalyser.py 8.1 KB

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