Beispiel #1
0
class PreciseEngine(WakeWordEnginePlugin):
    program_url = (
        'https://raw.githubusercontent.com/MycroftAI/'
        'precise-data/dist/{arch}/precise-engine.tar.gz'
    )
    model_url = (
        'https://raw.githubusercontent.com/MycroftAI/'
        'precise-data/models/{model_name}.tar.gz'
    )

    def __init__(self, rt, on_activation: Callable):
        super().__init__(rt, on_activation)

        exe_file = which('precise-engine')
        precise_folder = join(self.rt.paths.user_config, 'precise')
        if not exe_file:
            exe_file = join(precise_folder, 'precise-engine', 'precise-engine')
            download_extract_tar(
                self.program_url.format(arch=platform.machine()),
                precise_folder, check_md5=False, subdir='precise-engine',
                on_update=lambda: self.rt.interfaces.faceplate.text('Updating listener...'),
                on_complete=lambda: self.rt.interfaces.faceplate.reset()
            )
        log.debug('Using precise executable: ' + exe_file)

        model_folder = join(precise_folder, 'models', self.wake_word)
        model_file = join(model_folder, self.wake_word + '.pb')
        model_url = self.model_url.format(model_name=self.wake_word)
        download_extract_tar(model_url, model_folder, check_md5=True)

        from precise_runner import PreciseRunner, PreciseEngine
        engine = PreciseEngine(exe_file, model_file, chunk_size=1024)
        self.runner = PreciseRunner(engine, on_activation=on_activation)

    def startup(self):
        self.runner.start()

    def shutdown(self):
        self.runner.stop()

    def continue_listening(self):
        self.runner.play()

    def pause_listening(self):
        self.runner.pause()
Beispiel #2
0
class HotwordDetector(Thread):
    """
    Precise decoder to detect whether a keyword specified by `decoder_model`
    exists in a microphone input stream.

    :param decoder_model: decoder model file path, a string or a list of strings
    :param sensitivity: decoder sensitivity, a float of a list of floats.
                              The bigger the value, the more senstive the
                              decoder. If an empty list is provided, then the
                              default sensitivity in the model will be used.
    """
    def __init__(self,
                 keyword=None,
                 sensitivity=None,
                 detected_callback=None
                ):
                 
        super(HotwordDetector, self).__init__()
        sl = SettingLoader()
        self.settings = sl.settings
        self.paused_loop = False
        self.detected_callback = detected_callback
        self.sensitivity = sensitivity
        trigger_level = 3
        self.keyword = keyword
        self.found_keyword = False

        if not os.path.exists(RESOURCE_FILE):
            if self.downloadPreciseEngine():
                Utils.print_info("[Precise] Download complete")
            else:
                raise PreciseEngineNotFound("Error downloading precise engine, check your internet connection or try again later.")

        engine = PreciseEngine(RESOURCE_FILE, self.keyword)

        self.stream = ReadWriteStream()
        self.runner = PreciseRunner(engine,
                                    sensitivity=float(self.sensitivity),
                                    trigger_level=trigger_level,
                                    on_activation=self.activation
                                    )
        
        self.runner.start()
        self.pause()                                    # To avoid that precise starts detecting without beeing ready, we pause it right after start
        if self.settings.machine.startswith("arm"):     # Because importing tensorflow takes up to 10 seconds, we sleep a while
            Utils.print_info("Starting precise trigger")
            time.sleep(10)

    def run(self):
        logger.debug("detecting...")
        while True:
            if not self.paused_loop:
                data = self.stream.read()
                if len(data) > 0:
                    self.stream.write(data)

                if self.found_keyword:
                    self.pause()                          # We start pausing it here, to avoid double activations
                    message = "[Precise] Keyword detected"
                    Utils.print_info(message)
                    logger.debug(message)
                    self.detected_callback()

            time.sleep(0.01)
        logger.debug("finished")


    def activation(self):
        self.found_keyword = True

    def pause(self):
        self.runner.pause()
        self.paused_loop = True

    def unpause(self):
        self.runner.play()
        self.paused_loop = False
        self.found_keyword = False
    
    def downloadPreciseEngine(self):
        import json
        import requests
        import tarfile

        Utils.print_info("[Preicse] Precise engine not present, starting download now")
        url = "https://api.github.com/repos/MycroftAI/mycroft-precise/releases/latest"
        response = requests.get(url)
        if response.status_code == 200:
            download_url = None
            arch = self.settings.machine
            for asset in response.json()["assets"]:
                if arch in asset.get("name"):
                    if asset.get("name").startswith("precise-engine") and asset.get("name").endswith(".tar.gz"):
                        download_name = asset.get("name")
                        download_url = asset.get('browser_download_url')

            filepath = os.path.join(TOP_DIR, download_name)
            if download_url:
                Utils.print_info("[Precise] Downloading %s this can take a moment" % download_name)
                file = requests.get(download_url)
                if file.status_code == 200:
                    with open(filepath, 'wb') as f:
                        f.write(file.content)

                    with tarfile.open(filepath) as tar:
                        tar.extractall(path=TOP_DIR)
                    os.remove(filepath)
                    return True
        return False