def run_matching_synapse_from_order(cls, order_to_process, brain, settings, is_api_call=False): """ :param order_to_process: the spoken order sent by the user :param brain: Brain object :param settings: Settings object :param is_api_call: if True, the current call come from the API. This info must be known by launched Neuron :return: list of matched synapse """ # get our singleton LIFO lifo_buffer = LifoManager.get_singleton_lifo() # if the LIFO is not empty, so, the current order is passed to the current processing synapse as an answer if len(lifo_buffer.lifo_list) > 0: # the LIFO is not empty, this is an answer to a previous call return lifo_buffer.execute(answer=order_to_process, is_api_call=is_api_call) else: # the LIFO is empty, this is a new call # get a list of matched synapse from the order list_synapse_to_process = OrderAnalyser.get_matching_synapse(order=order_to_process, brain=brain) if not list_synapse_to_process: # the order analyser returned us an empty list return HookManager.on_order_not_found() else: HookManager.on_order_found() lifo_buffer.add_synapse_list_to_lifo(list_synapse_to_process) lifo_buffer.api_response.user_order = order_to_process execdata = lifo_buffer.execute(is_api_call=is_api_call) HookManager.on_processed_synapses() return execdata
def unpausing_trigger_process(self): """ If the trigger was in pause, this method will unpause it to listen again for the hotword """ logger.debug("Entering state: %s" % self.state) HookManager.on_waiting_for_trigger() self.trigger_instance.unpause() self.trigger_callback_called = False self.next_state()
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 pause_trigger_process(self): """ The trigger has been awaken, we pause it :return: """ logger.debug("[Order] Entering state: %s" % self.state) self.trigger_instance.pause() # if here, then the trigger has been called and paused HookManager.on_triggered() self.next_state()
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 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 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( "[MainController] Order listener callback called. Order to process: %s" % order) HookManager.on_stop_listening() self.order_to_process = order self.order_listener_callback_called = True
def start_trigger_process(self): """ This function will start the trigger thread that listen for the hotword """ logger.debug("[Order] Entering state: %s" % self.state) HookManager.on_waiting_for_trigger() self.trigger_instance = TriggerLauncher.get_trigger(settings=self.settings, callback=self.trigger_callback) self.trigger_callback_called = False self.trigger_instance.daemon = True # Wait that the kalliope trigger is pronounced by the user self.trigger_instance.start() self.next_state()
def start_order_listener_thread(self): """ Start the STT engine thread """ logger.debug("[Order] Entering state: %s" % self.state) HookManager.on_start_listening() # start listening for an order self.order_listener_callback_called = False self.order_listener = OrderListener(callback=self.order_listener_callback) self.order_listener.daemon = True self.order_listener.start() self.next_state()
def start_trigger_process(self): """ This function will start the trigger thread that listen for the hotword """ logger.debug("[Order] Entering state: %s" % self.state) self.trigger_instance = TriggerLauncher.get_trigger(settings=self.settings, callback=self.trigger_callback) self.trigger_callback_called = False self.trigger_instance.daemon = True # Wait that the kalliope trigger is pronounced by the user self.trigger_instance.start() HookManager.on_start() self.next_state()
def get_audio_from_stt(callback): """ Call the default STT to get an audio sample and return it into the callback method :param callback: A callback function """ HookManager.on_start_listening() # call the order listener ol = OrderListener(callback=callback) ol.start() ol.join() # wait that the STT engine has finish his job (or the neurotransmitter neuron will be killed) if ol.stt_instance is not None: ol.stt_instance.join() HookManager.on_stop_listening()
def set_mute_status(mute=False): """ Define is the mute status :param mute: Boolean. If false, Kalliope is voice is stopped """ logger.debug("[SettingEditor] mute. Switch trigger process to mute : %s" % mute) settings = SettingLoader().settings if mute: Utils.print_info("Kalliope now muted, voice has been stopped.") HookManager.on_mute() else: Utils.print_info("Kalliope now speaking.") HookManager.on_unmute() settings.options.mute = mute
def set_mute_status(mute=False): """ Define is the mute status :param mute: Boolean. If false, Kalliope is voice is stopped """ logger.debug( "[SettingEditor] mute. Switch trigger process to mute : %s" % mute) settings = SettingLoader().settings if mute: Utils.print_info("Kalliope now muted, voice has been stopped.") HookManager.on_mute() else: Utils.print_info("Kalliope now speaking.") HookManager.on_unmute() settings.options.mute = mute
def waiting_for_trigger_callback_thread(self): """ Method to print in debug that the main process is waiting for a trigger detection """ logger.debug("[Order] Entering state: %s" % self.state) if self.settings.options.deaf: # the user asked to deaf inside the deaf neuron Utils.print_info("Kalliope is deaf") self.trigger_instance.pause() else: Utils.print_info("Waiting for trigger detection") # this loop is used to keep the main thread alive while not self.trigger_callback_called: sleep(0.1) # if here, then the trigger has been called HookManager.on_triggered() self.next_state()
def set_deaf_status(trigger_instance, deaf=False): """ Define is the trigger is listening or not. :param trigger_instance: the trigger instance coming from the order. It will be paused or unpaused. :param deaf: Boolean. If true, kalliope is trigger is paused """ logger.debug("[MainController] deaf . Switch trigger process to deaf : %s" % deaf) settings = SettingLoader().settings if deaf: trigger_instance.pause() Utils.print_info("Kalliope now deaf, trigger has been paused") HookManager.on_deaf() else: trigger_instance.unpause() Utils.print_info("Kalliope now listening for trigger detection") HookManager.on_undeaf() settings.options.deaf = deaf
def analysing_order_thread(self): """ Start the order analyser with the caught order to process """ if self.order_to_process is None or self.order_to_process == "": logger.debug("[Order] No audio caught from analysing_order_thread") HookManager.on_stt_error() else: logger.debug("[Order] order in analysing_order_thread %s" % self.order_to_process) SynapseLauncher.run_matching_synapse_from_order(self.order_to_process, self.brain, self.settings, is_api_call=False) if self.skip_trigger: self.start_order_listener() else: self.unpause_trigger()
def analysing_order_thread(self): """ Start the order analyser with the caught order to process """ if self.order_to_process is None or self.order_to_process == "": logger.debug("[Order] No audio caught from analysing_order_thread") HookManager.on_stt_error() else: logger.debug("[Order] order in analysing_order_thread %s" % self.order_to_process) SynapseLauncher.run_matching_synapse_from_order(self.order_to_process, self.brain, self.settings, is_api_call=False) if self.skip_trigger: self.start_order_listener() else: self.start_trigger()
def set_mute_status(self, muted=False): """ Define is the trigger is listening or not :param muted: Boolean. If true, kalliope is muted """ logger.debug( "[MainController] Mute button pressed. Switch trigger process to muted: %s" % muted) if muted: self.trigger_instance.pause() self.is_trigger_muted = True Utils.print_info("Kalliope now muted") HookManager.on_mute() else: self.trigger_instance.unpause() self.is_trigger_muted = False Utils.print_info("Kalliope now listening for trigger detection") HookManager.on_unmute()
def set_deaf_status(trigger_instance, deaf=False): """ Define is the trigger is listening or not. :param trigger_instance: the trigger instance coming from the order. It will be paused or unpaused. :param deaf: Boolean. If true, kalliope is trigger is paused """ logger.debug( "[MainController] deaf . Switch trigger process to deaf : %s" % deaf) settings = SettingLoader().settings if deaf: trigger_instance.pause() Utils.print_info("Kalliope now deaf, trigger has been paused") HookManager.on_deaf() else: trigger_instance.unpause() Utils.print_info("Kalliope now listening for trigger detection") HookManager.on_undeaf() settings.options.deaf = deaf
def start_recording(self): # pyaudio can work but alsa-lib spiting out error messages, to avoid this I used a method to suppress the messages found on stackoverflow # https://stackoverflow.com/questions/7088672/pyaudio-working-but-spits-out-error-messages-each-time with self.noalsaerr(): audio = pyaudio.PyAudio() FORMAT = pyaudio.paInt32 if self.format == "paInt16": FORMAT = pyaudio.paInt16 if self.format == "paInt24": FORMAT = pyaudio.paInt24 stream = audio.open(format=FORMAT, channels=self.channels, rate=self.rate, input=True, frames_per_buffer=self.chunk) Utils.print_info("[ Recorder ] Is recording...") HookManager.on_start_listening() frames = [] for i in range(0, int(self.rate / self.chunk * self.seconds)): data = stream.read(self.chunk) frames.append(data) stream.stop_stream() stream.close() audio.terminate() HookManager.on_stop_listening() waveFile = wave.open(self.output, 'wb') waveFile.setnchannels(2) waveFile.setsampwidth(audio.get_sample_size(FORMAT)) waveFile.setframerate(self.rate) waveFile.writeframes(b''.join(frames)) waveFile.close() Utils.print_info("[ Recorder ] Record saved to %s" % self.output) if self.playback: self.playback_file(self.output)
def run(self): # run hook on_start HookManager.on_start() self.start_trigger()
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.")