Exemple #1
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)
Exemple #2
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)
Exemple #3
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)
Exemple #4
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)
Exemple #5
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
Exemple #7
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)
Exemple #8
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()
Exemple #9
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)
Exemple #10
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 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
Exemple #14
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)
Exemple #15
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.")