示例#1
0
    def __init__(self, **kwargs):
        """
        Class used by neuron for talking
        :param kwargs: Same parameter as the Child. Can contain info about the tts to use instead of the
        default one
        """
        # get the child who called the class
        child_name = self.__class__.__name__
        self.neuron_name = child_name

        sl = SettingLoader()
        self.settings = sl.settings
        brain_loader = BrainLoader()
        self.brain = brain_loader.brain

        self.tts = self._get_tts_object(settings=self.settings)

        # get templates if provided
        # Check if there is a template associate to the output message
        self.say_template = kwargs.get('say_template', None)
        # check if there is a template file associate to the output message
        self.file_template = kwargs.get('file_template', None)
        # keep the generated message
        self.tts_message = None
        # if the current call is api one
        self.is_api_call = kwargs.get('is_api_call', False)
        # boolean to know id the synapse is waiting for an answer
        self.is_waiting_for_answer = False
        # the synapse name to add the the buffer
        self.pending_synapse = None
        # a dict of parameters the user ask to save in short term memory
        self.kalliope_memory = kwargs.get('kalliope_memory', None)
        # parameters loaded from the order can be save now
        Cortex.save_parameter_from_order_in_memory(self.kalliope_memory)
示例#2
0
    def start_new_process(self, sound_arg):
        """
        Start mplayer process with the given sounds to play
        :param sound_arg:
        :type sound_arg: list of dicts [{name: link}, {name: link}, {name: link}]
        :return:
        """
        mplayer_exec_path = [self.mplayer_path]
        mplayer_options = ['-slave', '-quiet', '-af', 'volume=-15', '-loop']
        mplayer_options.append("0" if self.loop_option == "loop" else "1")

        mplayer_command = list()
        mplayer_command.extend(mplayer_exec_path)
        mplayer_command.extend(mplayer_options)

        for sound in sound_arg:
            for sound_name, sound_link in sound.items():
                mplayer_command.append(sound_link)

        logger.debug("[Background_sound_player] Mplayer cmd: %s" %
                     str(mplayer_command))
        Cortex.save("current_playing_background_sound", sound_name)

        # give the current file name played to the neuron template
        self.message['sound_name'] = sound_name
        self.message["sound_link"] = sound_link

        # run mplayer in background inside a new process
        fnull = open(os.devnull, 'w')
        pid = subprocess.Popen(mplayer_command, stdout=fnull, stderr=fnull).pid

        # store the pid in a file to be killed later
        self.store_pid(pid)
        logger.debug("[Background_sound_player] Mplayer started, pid: %s" %
                     pid)
示例#3
0
    def test_save_parameter_from_order_in_memory(self):
        # Test with a value that exist in the temp memory
        order_parameters = {
            "key1": "value1",
            "key2": "value2"
        }

        Cortex.temp = order_parameters

        dict_val_to_save = {"my_key_in_memory": "{{key1}}"}

        expected_dict = {"my_key_in_memory": "value1"}

        Cortex.save_parameter_from_order_in_memory(dict_val_to_save)

        self.assertDictEqual(expected_dict, Cortex.memory)

        # test with a value that does not exsit
        order_parameters = {
            "key1": "value1",
            "key2": "value2"
        }

        Cortex.temp = order_parameters
        dict_val_to_save = {"my_key_in_memory": "{{key3}}"}

        self.assertFalse(Cortex.save_parameter_from_order_in_memory(dict_val_to_save))
示例#4
0
    def test_save_parameter_from_order_in_memory(self):
        # Test with a value that exist in the temp memory
        order_parameters = {"key1": "value1", "key2": "value2"}

        Cortex.temp = order_parameters

        dict_val_to_save = {"my_key_in_memory": "{{key1}}"}

        expected_dict = {"my_key_in_memory": "value1"}

        Cortex.save_parameter_from_order_in_memory(dict_val_to_save)

        self.assertDictEqual(expected_dict, Cortex.memory)

        # test with a value that does not exist
        order_parameters = {"key1": "value1", "key2": "value2"}

        Cortex.temp = order_parameters
        dict_val_to_save = {"my_key_in_memory": "{{key3}}"}

        self.assertFalse(
            Cortex.save_parameter_from_order_in_memory(dict_val_to_save))

        # save a value with no brackets
        dict_val_to_save = {"my_key_in_memory": "my value"}
        expected_dict = {"my_key_in_memory": "my value"}

        self.assertTrue(
            Cortex.save_parameter_from_order_in_memory(dict_val_to_save))
        self.assertDictEqual(expected_dict, Cortex.memory)
    def __init__(self, **kwargs):
        """
        Class used by neuron for talking
        :param kwargs: Same parameter as the Child. Can contain info about the tts to use instead of the
        default one
        """
        # get the child who called the class
        child_name = self.__class__.__name__
        self.neuron_name = child_name

        sl = SettingLoader()
        self.settings = sl.settings
        brain_loader = BrainLoader()
        self.brain = brain_loader.brain

        self.tts = self._get_tts_object(settings=self.settings)

        # get templates if provided
        # Check if there is a template associate to the output message
        self.say_template = kwargs.get('say_template', None)
        # check if there is a template file associate to the output message
        self.file_template = kwargs.get('file_template', None)
        # keep the generated message
        self.tts_message = None
        # if the current call is api one
        self.is_api_call = kwargs.get('is_api_call', False)
        # boolean to know id the synapse is waiting for an answer
        self.is_waiting_for_answer = False
        # the synapse name to add the the buffer
        self.pending_synapse = None
        # a dict of parameters the user ask to save in short term memory
        self.kalliope_memory = kwargs.get('kalliope_memory', None)
        # parameters loaded from the order can be save now
        Cortex.save_parameter_from_order_in_memory(self.kalliope_memory)
示例#6
0
    def __init__(self, **kwargs):
        super(Editor, self).__init__(**kwargs)
        # the args from the neuron configuration
        listen_ip = kwargs.get('listen_ip', '0.0.0.0')
        port = kwargs.get('port', 8000)
        ignore_pattern = kwargs.get('ignore_pattern', None)
        dir_first = kwargs.get('dir_first', False)
        hide_hidden = kwargs.get('hide_hidden', False)
        page_title = kwargs.get('page_title', "Kalliope Editor")
        stop_server = kwargs.get('stop_server', False)

        if stop_server:
            self.stop_http_server()
            Utils.print_info("[ Editor ] Editor stopped")
        else:
            global IGNORE_PATTERN, DIRSFIRST, HIDEHIDDEN, PAGE_TITLE

            IGNORE_PATTERN = ignore_pattern
            DIRSFIRST = dir_first
            HIDEHIDDEN = hide_hidden
            PAGE_TITLE = page_title

            if self.stop_http_server():
                server = EditorThread(listen_ip, int(port))
                server.daemon = True
                server.start()
                Cortex.save('EditorServerThread', server)
示例#7
0
    def test_add_parameters_from_order(self):

        order_parameters = {"key1": "value1", "key2": "value2"}

        expected_temp_dict = {"key1": "value1", "key2": "value2"}

        Cortex.add_parameters_from_order(order_parameters)
        self.assertDictEqual(Cortex.temp, expected_temp_dict)
示例#8
0
    def test_save(self):
        key_to_save = "key1"
        value_to_save = "value1"

        expected_memory = {"key1": "value1"}

        Cortex.save(key=key_to_save, value=value_to_save)
        self.assertDictEqual(expected_memory, Cortex.memory)
示例#9
0
    def start_synapse_by_list_name(cls,
                                   list_name,
                                   brain=None,
                                   overriding_parameter_dict=None,
                                   new_lifo=False):
        """
        Start synapses by their name
        :param list_name: List of name of the synapse to launch
        :param brain: Brain instance
        :param overriding_parameter_dict: parameter to pass to neurons
        :param new_lifo: If True, ask the LifoManager to return a new lifo and not the singleton
        """
        logger.debug(
            "[SynapseLauncher] start_synapse_by_list_name called with synapse list: %s "
            % list_name)

        if list_name:
            if brain is None:
                brain = BrainLoader().brain

            if overriding_parameter_dict:
                # this dict is used by signals to pass parameter to neuron,
                # save in temp memory in case the user want to save in kalliope memory
                Cortex.add_parameters_from_order(overriding_parameter_dict)

            # get all synapse object
            list_synapse_object_to_start = list()
            for name in list_name:
                synapse_to_start = brain.get_synapse_by_name(synapse_name=name)
                if not synapse_to_start:
                    raise SynapseNameNotFound(
                        "[SynapseLauncher] The synapse name \"%s\" does not exist "
                        "in the brain file" % name)
                if synapse_to_start.enabled:
                    list_synapse_object_to_start.append(synapse_to_start)
                else:
                    logger.debug(
                        "[SynapseLauncher] Synapse not activated: %s " %
                        synapse_to_start)

            # run the LIFO with all synapse
            if new_lifo:
                lifo_buffer = LifoManager.get_new_lifo()
            else:
                lifo_buffer = LifoManager.get_singleton_lifo()
            list_synapse_to_process = list()
            for synapse in list_synapse_object_to_start:
                if synapse is not None:
                    new_matching_synapse = MatchedSynapse(
                        matched_synapse=synapse,
                        matched_order=None,
                        user_order=None,
                        overriding_parameter=overriding_parameter_dict)
                    list_synapse_to_process.append(new_matching_synapse)

            lifo_buffer.add_synapse_list_to_lifo(list_synapse_to_process)
            return lifo_buffer.execute(is_api_call=True)
        return None
示例#10
0
    def test_clean_parameter_from_order(self):
        Cortex.temp = {
            "key1": "value1",
            "key2": "value2"
        }

        Cortex.clean_parameter_from_order()
        expected_temp_dict = dict()
        self.assertDictEqual(expected_temp_dict, Cortex.memory)
示例#11
0
    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.kalliope_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_success(tts_message)
            # save in kalliope memory the last tts message
            Cortex.save("kalliope_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, Kalliope is muted")
            else:
                logger.debug(
                    "[NeuronModule] mute is False, make Kalliope 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 run_synapse_by_order(self):
        """
        Give an order to Kalliope via API like it was from a spoken one
        Test with curl
        curl -i --user admin:secret -H "Content-Type: application/json" -X POST \
        -d '{"order":"my order"}' http://localhost:5000/synapses/start/order

        In case of quotes in the order or accents, use a file
        cat post.json:
        {"order":"j'aime"}
        curl -i --user admin:secret -H "Content-Type: application/json" -X POST \
        --data @post.json http://localhost:5000/order/

        Can be used with mute flag
        curl -i --user admin:secret -H "Content-Type: application/json" -X POST \
        -d '{"order":"my order", "mute":"true"}' http://localhost:5000/synapses/start/order

        :return:
        """
        if not request.get_json() or 'order' not in request.get_json():
            data = {
                "Error": "Wrong parameters, 'order' not set"
            }
            return jsonify(error=data), 400

        order = request.get_json('order')

        # Store the mute value, then apply depending of the request parameters
        old_mute_value = self.settings.options.mute
        mute = utils.get_value_flag_from_request(http_request=request,
                                                 flag_to_find="mute",
                                                 is_boolean=True)
        if mute is not None:
            SettingEditor.set_mute_status(mute=mute)

        if order is not None:
            # get the order
            order_to_run = order["order"]
            logger.debug("[FlaskAPI] run_synapse_by_order: order to run -> %s" % order_to_run)
            api_response = SynapseLauncher.run_matching_synapse_from_order(order_to_run,
                                                                           self.brain,
                                                                           self.settings,
                                                                           is_api_call=True)

            Cortex.save('kalliope_last_order', order_to_run)
            data = jsonify(api_response)
            if mute is not None:
                SettingEditor.set_mute_status(mute=old_mute_value)
            return data, 201
        else:
            data = {
                "error": "order cannot be null"
            }
            if mute is not None:
                SettingEditor.set_mute_status(mute=old_mute_value)
            return jsonify(error=data), 400
示例#13
0
    def test_save(self):
        key_to_save = "key1"
        value_to_save = "value1"

        expected_memory = {
            "key1": "value1"
        }

        Cortex.save(key=key_to_save, value=value_to_save)
        self.assertDictEqual(expected_memory, Cortex.memory)
示例#14
0
    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.kalliope_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_success(tts_message)
            # save in kalliope memory the last tts message
            Cortex.save("kalliope_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, Kalliope is muted")
            else:
                logger.debug("[NeuronModule] mute is False, make Kalliope 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()
示例#15
0
    def test_save_neuron_parameter_in_memory(self):
        # test with a list of parameter with bracket
        neuron1_parameters = {"key1": "value1", "key2": "value2"}
        dict_val_to_save = {"my_key_in_memory": "{{key1}}"}
        expected_dict = {"my_key_in_memory": "value1"}
        Cortex.save_neuron_parameter_in_memory(
            kalliope_memory_dict=dict_val_to_save,
            neuron_parameters=neuron1_parameters)
        self.assertDictEqual(expected_dict, Cortex.memory)

        # test with a list of parameter with brackets and string
        self.setUp()  # clean
        neuron1_parameters = {"key1": "value1", "key2": "value2"}
        dict_val_to_save = {"my_key_in_memory": "string {{key1}}"}
        expected_dict = {"my_key_in_memory": "string value1"}
        Cortex.save_neuron_parameter_in_memory(
            kalliope_memory_dict=dict_val_to_save,
            neuron_parameters=neuron1_parameters)
        self.assertDictEqual(expected_dict, Cortex.memory)

        # test with a list of parameter with only a string. Neuron parameters are not used
        self.setUp()  # clean
        neuron1_parameters = {"key1": "value1", "key2": "value2"}
        dict_val_to_save = {"my_key_in_memory": "string"}
        expected_dict = {"my_key_in_memory": "string"}
        Cortex.save_neuron_parameter_in_memory(
            kalliope_memory_dict=dict_val_to_save,
            neuron_parameters=neuron1_parameters)
        self.assertDictEqual(expected_dict, Cortex.memory)

        # test with an empty list of parameter to save (no kalliope_memory set)
        self.setUp()  # clean
        neuron1_parameters = {"key1": "value1", "key2": "value2"}
        dict_val_to_save = None
        Cortex.save_neuron_parameter_in_memory(
            kalliope_memory_dict=dict_val_to_save,
            neuron_parameters=neuron1_parameters)
        self.assertDictEqual(dict(), Cortex.memory)

        # test with a neuron that return a dict in each parameter
        self.setUp()  # clean
        neuron1_parameters = {"key1": {"key2": "value2", "key3": "value3"}}
        dict_val_to_save = {"my_key_in_memory": "{{key1}}"}
        expected_dict = {
            "my_key_in_memory": {
                "key2": "value2",
                "key3": "value3"
            }
        }
        Cortex.save_neuron_parameter_in_memory(
            kalliope_memory_dict=dict_val_to_save,
            neuron_parameters=neuron1_parameters)
        self.assertDictEqual(expected_dict, Cortex.memory)
示例#16
0
 def order_listener_callback(self, order):
     """
     Receive an order, try to retrieve it in the brain.yml to launch to attached plugins
     :param order: the sentence received
     :type order: str
     """
     logger.debug("[Order] Order listener callback called. Order to process: %s" % order)
     HookManager.on_stop_listening()
     self.order_to_process = order
     self.order_listener_callback_called = True
     # save in kalliope memory the last order
     Cortex.save('kalliope_last_order', order)
示例#17
0
 def order_listener_callback(self, order):
     """
     Receive an order, try to retrieve it in the brain.yml to launch to attached plugins
     :param order: the sentence received
     :type order: str
     """
     logger.debug("[Order] Order listener callback called. Order to process: %s" % order)
     HookManager.on_stop_listening()
     self.order_to_process = order
     self.order_listener_callback_called = True
     # save in kalliope memory the last order
     Cortex.save('kalliope_last_order', order)
 def get_parameters(cls, synapse_order, user_order):
     """
     Class method to get all params coming from a string order. Returns a dict of key/value.
     """
     params = dict()
     if Utils.is_containing_bracket(synapse_order):
         params = cls._associate_order_params_to_values(
             user_order, synapse_order)
         logger.debug(
             "[NeuronParameterLoader.get_parameters]Parameters for order: %s"
             % params)
         # we place the dict of parameters load from order into a cache in Cortex so the user can save it later
         Cortex.add_parameters_from_order(params)
     return params
示例#19
0
    def test_add_parameters_from_order(self):

        order_parameters = {
            "key1": "value1",
            "key2": "value2"
        }

        expected_temp_dict = {
            "key1": "value1",
            "key2": "value2"
        }

        Cortex.add_parameters_from_order(order_parameters)
        self.assertDictEqual(Cortex.temp, expected_temp_dict)
示例#20
0
    def _replace_brackets_by_loaded_parameter(cls, neuron_parameters,
                                              loaded_parameters):
        """
        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))
        # 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 "kalliope_memory" to not override existing keys loaded form the order
        memory_dict = dict()
        memory_dict["kalliope_memory"] = Cortex.get_memory()
        if loaded_parameters is None:
            loaded_parameters = dict(
            )  # instantiate an empty dict in order to be able to add memory in it
        loaded_parameters.update(memory_dict)
        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):
                # 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
                    settings = cls.load_settings()
                    loaded_parameters.update(settings.variables)
                    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 kalliope core
                if key in "say_template" or key in "file_template" or key in "kalliope_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
示例#21
0
    def test_run_synapse_with_order(self):
        url = self.get_server_url() + "/synapses/start/order"
        headers = {"Content-Type": "application/json"}
        data = {"order": "test_order"}
        result = self.client.post(url, headers=headers, data=json.dumps(data))

        expected_content = {'status': 'complete',
                            'matched_synapses':
                                [
                                    {
                                        'matched_order': "test_order",
                                        'neuron_module_list':
                                            [
                                                {
                                                    'generated_message': 'test message', 'neuron_name': 'Say'
                                                }
                                            ],
                                        'synapse_name': 'test'
                                    }
                                ],
                            'user_order': "test_order"
                            }
        self.assertEqual(json.dumps(expected_content, sort_keys=True),
                         json.dumps(json.loads(result.get_data().decode('utf-8')), sort_keys=True))
        self.assertEqual(result.status_code, 201)
        # check that the cortex contains the last order
        self.assertEqual("test_order", Cortex.get_from_key("kalliope_last_order"))

        # test with a wrong parameter in a neuron
        data = {"order": "test_order_miss_configured_neuron"}
        result = self.client.post(url, headers=headers, data=json.dumps(data))
        self.assertEqual(result.status_code, 201)
示例#22
0
 def stop_http_server(self):
     running_server = Cortex.get_from_key("EditorServerThread")
     if running_server:
         Utils.print_info("[ Editor ] Editor is running, stopping now...")
         running_server.shutdown_server()
         while not running_server.is_down:
             time.sleep(0.1)
     return True
示例#23
0
    def test_get_memory(self):
        test_memory = {
            "key1": "value1",
            "key2": "value2"
        }

        Cortex.memory = test_memory
        self.assertDictEqual(test_memory, Cortex.get_memory())
示例#24
0
    def test_get_from_key(self):
        test_memory = {
            "key1": "value1",
            "key2": "value2"
        }

        Cortex.memory = test_memory
        expected_value = "value2"
        self.assertEqual(expected_value, Cortex.get_from_key("key2"))
示例#25
0
    def execute(self, answer=None, is_api_call=False, no_voice=False):
        """
        Process the LIFO list.
        
        The LIFO list contains multiple list of matched synapses.        
        For each list of matched synapse we process synapses inside        
        For each synapses we process neurons.        
        If a neuron add a Synapse list to the lifo, this synapse list is processed before executing the first list 
        in which we were in.
        
        :param answer: String answer to give the the last neuron which was waiting for an answer
        :param is_api_call: Boolean passed to all neuron in order to let them know if the current call comes from API
        :param no_voice: If true, the generated text will not be processed by the TTS engine
        :return: serialized APIResponse object
        """
        # store the answer if present
        self.answer = answer
        self.is_api_call = is_api_call
        self.no_voice = no_voice

        if not self.is_running:
            self.is_running = True

            try:
                # we keep looping over the LIFO til we have synapse list to process in it
                while self.lifo_list:
                    logger.debug(
                        "[LIFOBuffer] number of synapse list to process: %s" %
                        len(self.lifo_list))
                    try:
                        # get the last list of matched synapse in the LIFO
                        last_synapse_fifo_list = self.lifo_list[-1]
                        self._process_synapse_list(last_synapse_fifo_list)
                    except SynapseListAddedToLIFO:
                        continue
                    # remove the synapse list from the LIFO
                    self.lifo_list.remove(last_synapse_fifo_list)
                    # clean the cortex from value loaded from order as all synapses have been processed
                    Cortex.clean_parameter_from_order()
                self.is_running = False
                raise Serialize

            except Serialize:
                return self._return_serialized_api_response()
    def start_new_process(self, sound_arg):
        """
        Start mplayer process with the given sounds to play
        :param sound_arg:
        :type sound_arg: list of dicts [{name: link}, {name: link}, {name: link}]
        :return:
        """
        mplayer_exec_path = [self.mplayer_path]
        mplayer_options = [
            '-slave', '-quiet', '-af', 'volume=-10', '-volume',
            str(self.launch_volume), '-loop'
        ]
        mplayer_options.append("0" if self.loop_option == "loop" else "1")

        mplayer_command = list()
        mplayer_command.extend(mplayer_exec_path)
        mplayer_command.extend(mplayer_options)

        for sound in sound_arg:
            for sound_name, sound_link in sound.items():
                mplayer_command.append(sound_link)

        logger.debug("[Background_sound_player] Mplayer cmd: %s" %
                     str(mplayer_command))

        # give the current file name played to the neuron template
        self.message['sound_name'] = sound_name
        self.message["sound_link"] = sound_link

        # run mplayer in background inside a new process
        fnull = open(os.devnull, 'w')
        process = subprocess.Popen(mplayer_command,
                                   stdout=fnull,
                                   stderr=fnull,
                                   stdin=subprocess.PIPE,
                                   universal_newlines=True)
        self.lower_sound_for_speaking()

        Cortex.save("current_playing_background_sound", sound_name)
        Cortex.save("background_mplayer_popen", process)
        logger.debug("[Background_sound_player] Mplayer started, pid: %s" %
                     process.pid)
    def stop_last_process(self):
        """
        stop the last mplayer process launched by this neuron
        :return:
        """

        if self.mplayer_popen_obj is not None:
            logger.debug("[Background_sound_player] loaded pid: %s" %
                         self.mplayer_popen_obj.pid)
            self.mplayer_popen_obj.kill()
            logger.debug(
                "[Background_sound_player] mplayer process with pid %s killed"
                % self.mplayer_popen_obj.pid)
            Cortex.save("current_playing_background_sound",
                        "Aucun fond sonore lancé actuellement")
            Cortex.save("background_mplayer_popen", 'NIL')
        else:
            logger.debug(
                "[Background_sound_player] Popen object is None. Process already stopped"
            )
 def audio_analyser_callback(self, order):
     """
     Callback of the OrderListener. Called after the processing of the audio file
     This method will
     - call the Order Analyser to analyse the  order and launch corresponding synapse as usual.
     - get a list of launched synapse.
     - give the list to the main process via self.launched_synapses
     - notify that the processing is over via order_analyser_return
     :param order: string order to analyse
     :return:
     """
     logger.debug("[FlaskAPI] audio_analyser_callback: order to process -> %s" % order)
     api_response = SynapseLauncher.run_matching_synapse_from_order(order,
                                                                    self.brain,
                                                                    self.settings,
                                                                    is_api_call=True)
     self.api_response = api_response
     Cortex.save('kalliope_last_order', order)
     # this boolean will notify the main process that the order have been processed
     self.order_analyser_return = True
示例#29
0
    def execute(self, answer=None, is_api_call=False):
        """
        Process the LIFO list.

        The LIFO list contains multiple list of matched synapses.
        For each list of matched synapse we process synapses inside
        For each synapses we process neurons.
        If a neuron add a Synapse list to the lifo, this synapse list is processed before executing the first list
        in which we were in.

        :param answer: String answer to give the the last neuron which was waiting for an answer
        :param is_api_call: Boolean passed to all neuron in order to let them know if the current call comes from API
        :return: serialized APIResponse object
        """
        # store the answer if present
        self.answer = answer
        self.is_api_call = is_api_call

        try:
            if not self.is_running:
                self.is_running = True

                # we keep looping over the LIFO til we have synapse list to process in it
                while self.lifo_list:
                    logger.debug("[LIFOBuffer] number of synapse list to process: %s" % len(self.lifo_list))
                    try:
                        # get the last list of matched synapse in the LIFO
                        last_synapse_fifo_list = self.lifo_list[-1]
                        self._process_synapse_list(last_synapse_fifo_list)
                    except SynapseListAddedToLIFO:
                        continue
                    # remove the synapse list from the LIFO
                    self.lifo_list.remove(last_synapse_fifo_list)
                    # clean the cortex from value loaded from order as all synapses have been processed
                    Cortex.clean_parameter_from_order()
                self.is_running = False
                raise Serialize

        except Serialize:
            return self._return_serialized_api_response()
示例#30
0
    def __init__(self, **kwargs):
        super(Background_sound_player, self).__init__(**kwargs)

        self.state = kwargs.get('state', None)  # "on" / "off"
        self.sounds = kwargs.get(
            'sounds',
            None)  # "[{'title1': 'link1'}, {'title2': 'link2'}, ...]"
        self.random_option = kwargs.get(
            'random_option', "random-select-one"
        )  # "random-order-play" / "random-select-one" / "no-random"
        self.loop_option = kwargs.get('loop_option',
                                      'no-loop')  # "loop" / "no-loop"
        self.mplayer_path = kwargs.get('mplayer_path', "/usr/bin/mplayer")
        self.auto_stop_minutes = kwargs.get('auto_stop_minutes', None)

        self.currently_playing_sound = None

        # a dict of parameters the user ask to save in short term memory
        self.kalliope_memory = kwargs.get('kalliope_memory', None)
        # parameters loaded from the order can be save now
        Cortex.save_parameter_from_order_in_memory(self.kalliope_memory)
        Cortex.save("current_playing_background_sound",
                    "Aucun fond sonore lancé actuellement")

        # message dict that will be passed to the neuron template
        self.message = dict()

        # check if sent parameters are in good state
        if self._is_parameters_ok():
            if self.state == "off":
                self.stop_last_process()
                self.clean_pid_file()
                Cortex.save("current_playing_background_sound",
                            "Aucun fond sonore lancé actuellement")
            else:
                # we stop the last process if exist
                self.stop_last_process()

                # pick one sound randomly in all sounds entered
                if self.random_option == "random-select-one":
                    self.currently_playing_sound = [random.choice(self.sounds)]
                # play all sounds in random order
                elif self.random_option == "random-order-play":
                    random.shuffle(self.sounds)
                    self.currently_playing_sound = self.sounds
                # play all sounds the specified order
                else:
                    self.currently_playing_sound = self.sounds

                # then we can start a new process
                self.start_new_process(self.currently_playing_sound)

                # run auto stop thread
                if self.auto_stop_minutes:
                    thread_auto_stop = threading.Thread(
                        target=self.wait_before_stop)
                    thread_auto_stop.start()

            # give the message dict to the neuron template
            self.say(self.message)
示例#31
0
    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 "kalliope_memory" to not override existing keys loaded form the order
                memory_dict["kalliope_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 kalliope core
                if key in "say_template" or key in "file_template" or key in "kalliope_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
示例#32
0
    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))

        # add kalliope memory
        final_message_dict = dict()
        final_message_dict["kalliope_memory"] = Cortex.get_memory()

        if message_dict:
            final_message_dict.update(**message_dict)

        returned_message = t.render(final_message_dict)
        return returned_message
    def get_mplayer_popen_obj():
        ret_process = Cortex.get_from_key('background_mplayer_popen')
        if (ret_process == 'NIL'):
            ret_process = None

        return ret_process
示例#34
0
    def test_save_neuron_parameter_in_memory(self):

        # test with a list of parameter with bracket

        neuron1_parameters = {
            "key1": "value1",
            "key2": "value2"
        }

        dict_val_to_save = {"my_key_in_memory": "{{key1}}"}

        expected_dict = {"my_key_in_memory": "value1"}

        Cortex.save_neuron_parameter_in_memory(kalliope_memory_dict=dict_val_to_save,
                                               neuron_parameters=neuron1_parameters)

        self.assertDictEqual(expected_dict, Cortex.memory)

        # test with a list of parameter with brackets and string
        self.setUp()  # clean
        neuron1_parameters = {
            "key1": "value1",
            "key2": "value2"
        }

        dict_val_to_save = {"my_key_in_memory": "string {{key1}}"}

        expected_dict = {"my_key_in_memory": "string value1"}

        Cortex.save_neuron_parameter_in_memory(kalliope_memory_dict=dict_val_to_save,
                                               neuron_parameters=neuron1_parameters)

        self.assertDictEqual(expected_dict, Cortex.memory)

        # test with a list of parameter with only a string. Neuron parameters are not used
        self.setUp()  # clean
        neuron1_parameters = {
            "key1": "value1",
            "key2": "value2"
        }

        dict_val_to_save = {"my_key_in_memory": "string"}

        expected_dict = {"my_key_in_memory": "string"}

        Cortex.save_neuron_parameter_in_memory(kalliope_memory_dict=dict_val_to_save,
                                               neuron_parameters=neuron1_parameters)

        self.assertDictEqual(expected_dict, Cortex.memory)

        # test with an empty list of parameter to save (no kalliope_memory set)
        self.setUp()  # clean

        neuron1_parameters = {
            "key1": "value1",
            "key2": "value2"
        }

        dict_val_to_save = None

        Cortex.save_neuron_parameter_in_memory(kalliope_memory_dict=dict_val_to_save,
                                               neuron_parameters=neuron1_parameters)

        self.assertDictEqual(dict(), Cortex.memory)
示例#35
0
    def run(self):
        """
        Start the voice detector. For every `sleep_time` second it checks the
        audio buffer for triggering keywords. If detected, then call
        corresponding function in `detected_callback`, which can be a single
        function (single model) or a list of callback functions (multiple
        models). Every loop it also calls `interrupt_check` -- if it returns
        True, then breaks from the loop and return.

        :param detected_callback: a function or list of functions. The number of
                                  items must match the number of models in
                                  `decoder_model`.
        :param interrupt_check: a function that returns True if the main loop
                                needs to stop.
        :param float sleep_time: how much time in second every loop waits.
        :param audio_recorder_callback: if specified, this will be called after
                                        a keyword has been spoken and after the
                                        phrase immediately after the keyword has
                                        been recorded. The function will be
                                        passed the name of the file where the
                                        phrase was recorded.
        :param silent_count_threshold: indicates how long silence must be heard
                                       to mark the end of a phrase that is
                                       being recorded.
        :param recording_timeout: limits the maximum length of a recording.
        :return: None
        """
        if self.interrupt_check():
            logger.debug("detect voice return")
            return

        tc = type(self.detected_callback)
        if tc is not list:
            self.detected_callback = [self.detected_callback]
        if len(self.detected_callback) == 1 and self.num_hotwords > 1:
            self.detected_callback *= self.num_hotwords

        assert self.num_hotwords == len(self.detected_callback), \
            "Error: hotwords in your models (%d) do not match the number of " \
            "callbacks (%d)" % (self.num_hotwords, len(self.detected_callback))

        logger.debug("detecting...")

        SR = SpeechRecorder()

        while not self.kill_received:
            #if not self.paused:
            if self.interrupt_check():
                logger.debug("detect voice break")
                break
            data = self.ring_buffer.get()

            if len(data) == 0:
                time.sleep(self.sleep_time)
                continue
            self.saveMessage(
                data
            )  # Save trigger data so it can be append to the record for STT
            status = self.detector.RunDetection(data)

            if status > 0:  #key word found
                SR.start()  # Start the speech recorder
                Utils.print_info("Keyword " + self.keyword_names[status] +
                                 " detected")
                Cortex.save(
                    'kalliope_trigger_called', self.keyword_names[status]
                )  # I save it to the Cortex, to use it by another neuron
                # for changing the tts acording to the trigger name
                HookManager.on_triggered()
                callback = self.detected_callback[status - 1]
                if callback is not None:
                    callback()

            if status == -1:
                logger.warning(
                    "Error initializing streams or reading audio data")

        logger.debug("finished.")
示例#36
0
    def test_clean_parameter_from_order(self):
        Cortex.temp = {"key1": "value1", "key2": "value2"}

        Cortex.clean_parameter_from_order()
        expected_temp_dict = dict()
        self.assertDictEqual(expected_temp_dict, Cortex.memory)
示例#37
0
    def start_new_process(self, sound_arg):  #Start mplayer process
        """
        Start mplayer process with the given sounds to play
        :param sound_arg:
        :type sound_arg: list of dicts [{name: link}, {name: link}, {name: link}]
        :return:
        """

        currently_playing_sound = None

        mplayer_exec_path = [self.mplayer_path]
        mplayer_options = ['-slave', '-quiet', '-af']
        mplayer_volume = ['volume']
        mplayer_volume[0] = "volume=" + self.volume
        mplayer_loop = ['-loop']
        mplayer_loop.append("0" if self.loop_option == "loop" else "1")
        # mplayer { 1.avi - loop 2 2.avi } -loop 3 > La commande  jouera les fichiers dans cet ordre: 1, 1, 2, 1, 1, 2, 1, 1, 2. "-loop 0" tournera a l'infini

        first_sound_name, first_sound_link = list(sound_arg[0].items())[0]
        first_sound_link = str(first_sound_link)
        # Pick one sound randomly in all sounds entered. currently_playing_sound will have only one entry
        # Need anyway to add "-playlist" if the link is a TXT playlist. But this playlist will be read with no shuffle option
        if self.random_option == "random-select-one":
            currently_playing_sound = [random.choice(sound_arg)]
            if (first_sound_link)[-4:] == ".txt":
                mplayer_loop.append("-playlist")
        # play all sounds in random order if there is no TXT playlist
        # at this stage, the list either only TXT or playable files (if not it should has raised an error in _check_sounds function
        # if the links are then TXT playlist, one will be selected. Otherwise, shuffle parameter is added to MPLAYER commands > need "-playlist" for TXT playlist
        elif self.random_option == "random-order-play":
            mplayer_loop.append("-shuffle")
            if str(
                    first_sound_link
            )[-4:] == ".txt":  # if it is a TXT (then like all others), need to randomly select one
                currently_playing_sound = [random.choice(sound_arg)]
                mplayer_loop.append("-playlist")
            else:
                currently_playing_sound = sound_arg
        # play all sounds the specified order
        else:
            if str(first_sound_link
                   )[-4:] == ".txt":  # if it is a TXT (then like all others)
                mplayer_loop.append(
                    "-playlist")  # then indicate that this is a playlist
                currently_playing_sound = sound_arg[
                    0]  # and select the first playlist
            else:
                currently_playing_sound = sound_arg  # else the list is simply copied

        mplayer_command = list()
        mplayer_command.extend(mplayer_exec_path)
        mplayer_command.extend(mplayer_options)
        mplayer_command.extend(mplayer_volume)
        mplayer_command.extend(mplayer_loop)
        for sound in currently_playing_sound:
            for sound_name, sound_link in sound.items():
                mplayer_command.append(sound_link)

        logger.debug("[Background_sound_player] Mplayer cmd: %s" %
                     str(mplayer_command))
        Cortex.save("current_playing_background_sound", sound_name)

        # give the current file name played to the neuron template
        self.message['sound_name'] = sound_name
        self.message["sound_link"] = sound_link

        # run mplayer in background inside a new process
        fnull = open(os.devnull, 'w')
        # mplayer_command = "mplayer -slave -quiet -af volume=-20 -loop 0 -shuffle -playlist /home/pi/kalliope_starter_fr/resources/sounds/MP3/Florian/*.*"
        pid = subprocess.Popen(mplayer_command, stdout=fnull, stderr=fnull).pid

        # store the pid in a file to be killed later
        self.store_pid(pid)
        logger.debug("[Background_sound_player] Mplayer started, pid: %s" %
                     pid)
示例#38
0
    def test_get_memory(self):
        test_memory = {"key1": "value1", "key2": "value2"}

        Cortex.memory = test_memory
        self.assertDictEqual(test_memory, Cortex.get_memory())
示例#39
0
    def test_get_from_key(self):
        test_memory = {"key1": "value1", "key2": "value2"}

        Cortex.memory = test_memory
        expected_value = "value2"
        self.assertEqual(expected_value, Cortex.get_from_key("key2"))