def get_list_match_synapse(cls, order, synapse_order_tuple): list_match_synapse = list() for synapse in cls.brain.synapses: if synapse.enabled: for signal in synapse.signals: # we are only concerned by synapse with a order type of signal if signal.name == "order": # get the type of matching expected, by default "normal" expected_matching_type = "normal" signal_order = None if isinstance(signal.parameters, str) or isinstance(signal.parameters, six.text_type): signal_order = signal.parameters if isinstance(signal.parameters, dict): try: signal_order = signal.parameters["text"] except KeyError: logger.debug("[OrderAnalyser] Warning, missing parameter 'text' in order. " "Order will be skipped") continue expected_matching_type = cls.get_matching_type(signal) order = cls.order_correction(order, signal) if cls.is_order_matching(user_order=order, signal_order=signal_order, expected_order_type=expected_matching_type): # the order match the synapse, we add it to the returned list logger.debug("Order found! Run synapse name: %s" % synapse.name) Utils.print_info("Brain: order recognized") Utils.print_success(" * Running synapse \"%s\"" % synapse.name) list_match_synapse.append(synapse_order_tuple(synapse=synapse, order=signal_order)) return list_match_synapse
def test_remove_spaces_in_brackets(self): """ Test the Utils remove_spaces_in_brackets """ sentence = "This is the {{ bracket }}" expected_result = "This is the {{bracket}}" self.assertEqual(Utils.remove_spaces_in_brackets(sentence=sentence), expected_result, "Fail to remove spaces in one bracket") sentence = "This is the {{ bracket }} {{ second }}" expected_result = "This is the {{bracket}} {{second}}" self.assertEqual(Utils.remove_spaces_in_brackets(sentence=sentence), expected_result, "Fail to remove spaces in two brackets") # test with json sentence = "{\"params\": {\"apikey\": \"ISNOTMYPASSWORD\", " \ "\"query\": \"met le chauffage a {{ valeur }} degres\"}}" expected_result = "{\"params\": {\"apikey\": \"ISNOTMYPASSWORD\", " \ "\"query\": \"met le chauffage a {{valeur}} degres\"}}" self.assertEqual(Utils.remove_spaces_in_brackets(sentence=sentence), expected_result, "Fail to remove spaces in two brackets")
def say(self, message): """ USe TTS to speak out loud the Message. A message can be a string, a list or a dict If it's a string, simply use the TTS with the message If it's a list, we select randomly a string in the list and give it to the TTS If it's a dict, we use the template given in parameter to create a string that we give to the TTS :param message: Can be a String or a dict or a list .. raises:: TTSModuleNotFound """ logger.debug("[NeuronModule] Say() called with message: %s" % message) tts_message = None # we can save parameters from the neuron in memory Cortex.save_neuron_parameter_in_memory(self.brain_memory, message) if isinstance(message, str) or isinstance(message, six.text_type): logger.debug("[NeuronModule] message is string") tts_message = message if isinstance(message, list): logger.debug("[NeuronModule] message is list") tts_message = random.choice(message) if isinstance(message, dict): logger.debug("[NeuronModule] message is dict") tts_message = self._get_message_from_dict(message) if tts_message is not None: logger.debug("[NeuronModule] tts_message to say: %s" % tts_message) self.tts_message = tts_message Utils.print_info("Player Engine: " + tts_message) # save in brain memory the last tts message Cortex.save("brain_last_tts_message", tts_message) # process the audio only if the mute flag is false if self.settings.options.mute: logger.debug("[NeuronModule] mute is True, Brain.ai is muted") else: logger.debug( "[NeuronModule] mute is False, make Brain.ai speaking") HookManager.on_start_speaking() # get the instance of the TTS module tts_folder = None if self.settings.resources: tts_folder = self.settings.resources.tts_folder tts_module_instance = Utils.get_dynamic_class_instantiation( package_name="tts", module_name=self.tts.name, parameters=self.tts.parameters, resources_dir=tts_folder) # generate the audio file and play it tts_module_instance.say(tts_message) HookManager.on_stop_speaking()
def __init__(self, file_path=None): self.file_path = file_path if self.file_path is None: self.file_path = Utils.get_real_file_path(FILE_NAME) else: self.file_path = Utils.get_real_file_path(file_path) # if the returned file path is none, the file doesn't exist if self.file_path is None: raise SettingNotFound("Settings.yml file not found") self.yaml_config = self._get_yaml_config() self.settings = self._get_settings()
def test_find_all_matching_brackets(self): """ Test the Utils find all matching brackets """ sentence = "This is the {{bracket}}" expected_result = ["{{bracket}}"] self.assertEqual(Utils.find_all_matching_brackets(sentence=sentence), expected_result, "Fail to match one bracket") sentence = "This is the {{bracket}} {{second}}" expected_result = ["{{bracket}}", "{{second}}"] self.assertEqual(Utils.find_all_matching_brackets(sentence=sentence), expected_result, "Fail to match two brackets")
def _replace_brackets_by_loaded_parameter(cls, neuron_parameters, loaded_parameters=dict()): """ Receive a value (which can be a str or dict or list) and instantiate value in double brace bracket by the value specified in the loaded_parameters dict. This method will call itself until all values has been instantiated :param neuron_parameters: value to instantiate. Str or dict or list :param loaded_parameters: dict of parameters """ logger.debug("[NeuronLauncher] replacing brackets from %s, using %s" % (neuron_parameters, loaded_parameters)) if isinstance(neuron_parameters, str) or isinstance(neuron_parameters, six.text_type): # replace bracket parameter only if the str contains brackets if Utils.is_containing_bracket(neuron_parameters): settings = cls.load_settings() # Priority to memory over the variables loaded_parameters.update(settings.variables) memory_dict = dict() # add variables from the short term memory to the list of loaded parameters that can be used in a template # the final dict is added into a key "brain_memory" to not override existing keys loaded form the order memory_dict["brain_memory"] = Cortex.get_memory() loaded_parameters.update(memory_dict) # check that the parameter to replace is available in the loaded_parameters dict if cls._neuron_parameters_are_available_in_loaded_parameters(neuron_parameters, loaded_parameters): # add parameters from global variable into the final loaded parameter dict neuron_parameters = jinja2.Template(neuron_parameters).render(loaded_parameters) neuron_parameters = Utils.encode_text_utf8(neuron_parameters) return str(neuron_parameters) else: raise NeuronParameterNotAvailable return neuron_parameters if isinstance(neuron_parameters, dict): returned_dict = dict() for key, value in neuron_parameters.items(): # following keys are reserved by brain core if key in "say_template" or key in "file_template" or key in "brain_memory" \ or key in "from_answer_link": returned_dict[key] = value else: returned_dict[key] = cls._replace_brackets_by_loaded_parameter(value, loaded_parameters) return returned_dict if isinstance(neuron_parameters, list): returned_list = list() for el in neuron_parameters: templated_value = cls._replace_brackets_by_loaded_parameter(el, loaded_parameters) returned_list.append(templated_value) return returned_list # in all other case (boolean or int for example) we return the value as it return neuron_parameters
def save_neuron_parameter_in_memory(cls, brain_memory_dict, neuron_parameters): """ receive a dict of value send by the child neuron save in brain memory all value E.g dict_parameter_to_save = {"my_key_to_save_in_memory": "{{ output_val_from_neuron }}"} neuron_parameter = {"output_val_from_neuron": "this_is_a_value" } then the cortex will save in memory the key "my_key_to_save_in_memory" and attach the value "this_is_a_value" :param neuron_parameters: dict of parameter the neuron has processed and send to the neurone module to be processed by the TTS engine :param brain_memory_dict: a dict of key value the user want to save from the dict_neuron_parameter """ if brain_memory_dict is not None: logger.debug("[Cortex] save_memory - User want to save: %s" % brain_memory_dict) logger.debug("[Cortex] save_memory - Available parameters in the neuron: %s" % neuron_parameters) for key, value in brain_memory_dict.items(): # ask the cortex to save in memory the target "key" if it was in parameters of the neuron if isinstance(neuron_parameters, dict): if Utils.is_containing_bracket(value): value = jinja2.Template(value).render(neuron_parameters) Cortex.save(key, value)
def test_get_next_value_list(self): # Success list_to_test = {1, 2, 3} self.assertEqual( Utils.get_next_value_list(list_to_test), 2, "Fail to match the expected next value from the list") # Failure list_to_test = {1} self.assertEqual( Utils.get_next_value_list(list_to_test), None, "Fail to ensure there is no next value from the list") # Behaviour list_to_test = {} self.assertEqual(Utils.get_next_value_list(list_to_test), None, "Fail to ensure the empty list return None value")
def test_get_current_file_parent_path(self): """ Expect to get back the parent path file """ path_to_test = "../brain/core/Utils" expected_result = os.path.normpath("../brain/core") self.assertEqual( Utils.get_current_file_parent_path(path_to_test), expected_result, "fail getting the parent parent path from the given path")
def test_encode_text_utf8(self): """ Test encoding the text in utf8 """ sentence = "kâllìöpé" if sys.version_info[0] < 3: sentence = sentence.decode('utf8') expected_sentence = "kâllìöpé" self.assertEqual(Utils.encode_text_utf8(text=sentence), expected_sentence)
def serialize(self): """ This method allows to serialize in a proper way this object :return: A dict of name and parameters :rtype: Dict """ self.tts_message = Utils.encode_text_utf8(self.tts_message) return { 'neuron_name': self.neuron_name, 'generated_message': self.tts_message }
def start_neuron(cls, neuron, parameters_dict=dict()): """ Execute each neuron from the received neuron_list. Replace parameter if exist in the received dict of parameters_dict :param neuron: 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) """ if neuron.parameters is not None: try: neuron.parameters = cls._replace_brackets_by_loaded_parameter(neuron.parameters, parameters_dict) except NeuronParameterNotAvailable: Utils.print_danger("Missing parameter in neuron %s. Execution skipped" % neuron.name) return None try: instantiated_neuron = NeuronLauncher.launch_neuron(neuron) except NeuronExceptions as e: Utils.print_danger("ERROR: Fail to execute neuron '%s'. " '%s' ". -> Execution skipped" % (neuron.name, e.message)) return None return instantiated_neuron
def _get_file_template(cls, file_template, message_dict): real_file_template_path = Utils.get_real_file_path(file_template) if real_file_template_path is None: raise TemplateFileNotFoundException( "Template file %s not found in templates folder" % real_file_template_path) # load the content of the file as template t = Template(cls._get_content_of_file(real_file_template_path)) returned_message = t.render(**message_dict) return returned_message
def _get_split_order_without_bracket(order): """ Get an order with bracket inside like: "hello my name is {{ name }}. return a list of string without bracket like ["hello", "my", "name", "is"] :param order: sentence to split :return: list of string without bracket """ matches = Utils.find_all_matching_brackets(order) for match in matches: order = order.replace(match, "") # then split split_order = order.split() return split_order
def _neuron_parameters_are_available_in_loaded_parameters(string_parameters, loaded_parameters): """ Check that all parameters in brackets are available in the loaded_parameters dict E.g: string_parameters = "this is a {{ parameter1 }}" Will return true if the loaded_parameters looks like the following loaded_parameters { "parameter1": "a value"} :param string_parameters: The string that contains one or more parameters in brace brackets :param loaded_parameters: Dict of parameter :return: True if all parameters in brackets have an existing key in loaded_parameters dict """ list_parameters_with_brackets = Utils.find_all_matching_brackets(string_parameters) # remove brackets to keep only the parameter name for parameter_with_brackets in list_parameters_with_brackets: parameter = Utils.remove_spaces_in_brackets(parameter_with_brackets) parameter = parameter.replace("{{", "").replace("}}", "") if loaded_parameters is None or parameter not in loaded_parameters: Utils.print_danger("The parameter %s is not available in the order" % str(parameter)) return False return True
def launch_neuron(cls, neuron): """ Start a neuron plugin :param neuron: neuron object :type neuron: Neuron :return: """ logger.debug("Run neuron: \"%s\"" % (neuron.__str__())) settings = cls.load_settings() neuron_folder = None if settings.resources: neuron_folder = settings.resources.neuron_folder return Utils.get_dynamic_class_instantiation(package_name="neurons", module_name=neuron.name, parameters=neuron.parameters, resources_dir=neuron_folder)
def test_get_dynamic_class_instantiation(self): """ Test that an instance as been instantiate properly. """ sl = SettingLoader() sl.settings.resource_dir = '/var/tmp/test/resources' neuron = Neuron( name='Say', parameters={'message': 'test dynamic class instantiate'}) self.assertTrue( isinstance( Utils.get_dynamic_class_instantiation( package_name="neurons", module_name=neuron.name.capitalize(), parameters=neuron.parameters, resources_dir='/var/tmp/test/resources'), Say), "Fail instantiate a class")
def test_is_containing_bracket(self): # Success order_to_test = "This test contains {{ bracket }}" self.assertTrue( Utils.is_containing_bracket(order_to_test), "Fail returning True when order contains spaced brackets") order_to_test = "This test contains {{bracket }}" self.assertTrue( Utils.is_containing_bracket(order_to_test), "Fail returning True when order contains right spaced bracket") order_to_test = "This test contains {{ bracket}}" self.assertTrue( Utils.is_containing_bracket(order_to_test), "Fail returning True when order contains left spaced bracket") order_to_test = "This test contains {{bracket}}" self.assertTrue( Utils.is_containing_bracket(order_to_test), "Fail returning True when order contains no spaced bracket") # Failure order_to_test = "This test does not contain bracket" self.assertFalse(Utils.is_containing_bracket(order_to_test), "Fail returning False when order has no brackets") # Behaviour order_to_test = "" self.assertFalse(Utils.is_containing_bracket(order_to_test), "Fail returning False when no order") # Behaviour int order_to_test = 6 self.assertFalse(Utils.is_containing_bracket(order_to_test), "Fail returning False when an int") # Behaviour unicode order_to_test = "j'aime les goûters l'été" self.assertFalse(Utils.is_containing_bracket(order_to_test), "Fail returning False when an int")
def _get_variables(settings): """ Return the dict of variables from the settings. :param settings: The YAML settings file :return: dict """ variables = dict() try: variables_files_name = settings["var_files"] # In case files are declared in settings.yml, make sure brain can access them. for files in variables_files_name: var = Utils.get_real_file_path(files) if var is None: raise SettingInvalidException( "Variables file %s not found" % files) else: variables.update(YAMLLoader.get_config(var)) return variables except KeyError: # User does not provide this settings return dict()
def load_stt_plugin(self): if self.stt is None: self.stt_module_name = self.settings.default_stt_name logger.debug("[OrderListener] stt module name : %s" % self.stt_module_name) for stt_object in self.settings.stts: if stt_object.name == self.stt_module_name: stt_object.parameters["callback"] = self.callback # add the audio file path to the list of parameter if set if self.audio_file_path is not None: stt_object.parameters[ "audio_file_path"] = self.audio_file_path stt_folder = None if self.settings.resources: stt_folder = self.settings.resources.stt_folder return Utils.get_dynamic_class_instantiation( package_name='stt', module_name=stt_object.name.capitalize(), parameters=stt_object.parameters, resources_dir=stt_folder)
def save_parameter_from_order_in_memory(cls, order_parameters): """ Save key from the temp dict (where parameters loaded from the voice order where placed temporary) into the memory dict :param order_parameters: dict of key to save. {'key_name_in_memory': 'key_name_in_temp_dict'} :return True if a value has been saved in the brain memory """ order_saved = False if order_parameters is not None: logger.debug("[Cortex] save_parameter_from_order_in_memory - User want to save: %s" % order_parameters) logger.debug("[Cortex] save_parameter_from_order_in_memory - Available parameters in orders: %s" % cls.temp) for key, value in order_parameters.items(): # ask the cortex to save in memory the target "key" if it was in the order if Utils.is_containing_bracket(value): # if the key exist in the temp dict we can load it with jinja value = jinja2.Template(value).render(Cortex.temp) if value: Cortex.save(key, value) order_saved = True return order_saved
def is_ordered_strict_matching(cls, user_order, signal_order): """ True if : - all word in the user_order are present in the signal_order - no additional word - same order as word present in signal_order :param user_order: order from the user :param signal_order: order in the signal :return: Boolean """ logger.debug( "[OrderAnalyser] ordered_strict_matching called with user_order: %s, signal_order: %s" % (user_order, signal_order)) if cls.is_normal_matching(user_order=user_order, signal_order=signal_order) and \ cls.is_strict_matching(user_order=user_order, signal_order=signal_order): # if the signal order contains bracket, we need to instantiate it with loaded parameters from the user order if Utils.is_containing_bracket(signal_order): signal_order = cls._get_instantiated_order_signal_from_user_order(signal_order, user_order) split_user_order = user_order.split() split_signal_order = signal_order.split() return split_user_order == split_signal_order return False
def test_get_real_file_path(self): """ Expect to load the proper file following the order : - Provided absolute path - Current user path + file_name - /etc/brain + file_name - /path/to/brain/ +file_name """ ### # Test the absolute path dir_path = "/tmp/brain/tests/" file_name = "test_real_file_path" absolute_path_to_test = os.path.join(dir_path, file_name) expected_result = absolute_path_to_test if not os.path.exists(dir_path): os.makedirs(dir_path) # touch the file open(absolute_path_to_test, 'a').close() self.assertEqual(Utils.get_real_file_path(absolute_path_to_test), expected_result, "Fail to match the given absolute path ") # Clean up if os.path.exists(absolute_path_to_test): os.remove(absolute_path_to_test) ### # test the Current path file_name = "test_real_file_path" expected_result = os.getcwd() + os.sep + file_name # touch the file open(file_name, 'a').close() self.assertEqual(Utils.get_real_file_path(file_name), expected_result, "Fail to match the Current path ") # Clean up if os.path.exists(file_name): os.remove(file_name) ### # test /etc/brain # /!\ need permissions # dir_path = "/etc/brain/" # file_name = "test_real_file_path" # path_to_test = os.path.join(dir_path,file_name) # expected_result = "/etc/brain" + os.sep + file_name # if not os.path.exists(dir_path): # os.makedirs(dir_path) # # # touch the file # open(path_to_test, 'a').close() # # self.assertEquals(Utils.get_real_file_path(file_name), # expected_result, # "Fail to match the /etc/brain path") # # Clean up # if os.path.exists(file_name): # os.remove(file_name) ### # /an/unknown/path/brain/ dir_path = "../brain/" file_name = "test_real_file_path" path_to_test = os.path.join(dir_path, file_name) expected_result = os.path.normpath(os.getcwd() + os.sep + os.pardir + os.sep + "brain" + os.sep + file_name) if not os.path.exists(dir_path): os.makedirs(dir_path) # touch the file open(path_to_test, 'a').close() self.assertEqual(Utils.get_real_file_path(file_name), expected_result, "Fail to match the /an/unknown/path/brain path") # Clean up if os.path.exists(expected_result): os.remove(expected_result)
def load_stt_correction_file(cls, stt_correction_file): stt_correction_file_path = Utils.get_real_file_path(stt_correction_file) stt_correction_file = open(stt_correction_file_path, "r") stt_correction = yaml.load(stt_correction_file) return stt_correction