Ejemplo n.º 1
0
    def load_phonemes(self, key):
        """Load phonemes from cache file.

        Arguments:
            Key:    Key identifying phoneme cache
        """
        pho_file = os.path.join(self.cache_dir,    key + ".pho")
        if os.path.exists(pho_file):
            try:
                with open(pho_file, "r") as cachefile:
                    phonemes = cachefile.read().strip()
                return phonemes
            except Exception:
                LOG.debug("Failed to read .PHO from cache")
        return None
Ejemplo n.º 2
0
 def __init__(self):
     path = None
     # TODO check system config platform and go directly to correct path if it exists
     paths = [
         "/opt/venvs/mycroft-core/lib/python3.7/site-packages/",  # mark1/2
         "/opt/venvs/mycroft-core/lib/python3.4/site-packages/ ",  # old mark1 installs
         "/home/pi/mycroft-core"  # picroft
     ]
     for p in paths:
         p = join(p, "mycroft", "configuration", "mycroft.conf")
         if isfile(p):
             path = p
     super().__init__(path)
     if not self.path or not isfile(self.path):
         LOG.warning("mycroft root path not found")
Ejemplo n.º 3
0
def discover_hivemind(name="JarbasVoiceTerminal",
                      access_key="RESISTENCEisFUTILE",
                      crypto_key="resistanceISfutile"):
    discovery = LocalDiscovery()
    headers = HiveMindConnection.get_headers(name, access_key)

    while True:
        LOG.info("Scanning...")
        for node_url in discovery.scan():
            LOG.info("Fetching Node data: {url}".format(url=node_url))
            node = discovery.nodes[node_url]
            node.connect(crypto_key=crypto_key,
                         node_type=JarbasVoiceTerminal,
                         headers=headers)
        sleep(5)
Ejemplo n.º 4
0
    def load_phonemes(self, key):
        """
            Load phonemes from cache file.

            Args:
                Key:    Key identifying phoneme cache
        """
        pho_file = os.path.join(get_cache_directory("tts"), key + ".pho")
        if os.path.exists(pho_file):
            try:
                with open(pho_file, "r") as cachefile:
                    phonemes = json.load(cachefile)
                return phonemes
            except Exception as e:
                LOG.error("Failed to read .PHO from cache ({})".format(e))
        return None
Ejemplo n.º 5
0
    def save_phonemes(self, key, phonemes):
        """
            Cache phonemes

            Args:
                key:        Hash key for the sentence
                phonemes:   phoneme string to save
        """

        cache_dir = get_cache_directory("tts")
        pho_file = os.path.join(cache_dir, key + ".pho")
        try:
            with open(pho_file, "w") as cachefile:
                cachefile.write(json.dumps(phonemes))
        except Exception:
            LOG.exception("Failed to write {} to cache".format(pho_file))
Ejemplo n.º 6
0
 def get_skills(self):
     start = time.time()
     self._response = None
     self.waiting = True
     self.bus.emit(
         Message("intent.service.skills.get",
                 context={
                     "destination": "intent_service",
                     "source": "intent_api"
                 }))
     while self.waiting and time.time() - start <= self.timeout:
         time.sleep(0.3)
     if time.time() - start > self.timeout:
         LOG.error("Intent Service timed out!")
         return None
     return self._response["skills"]
Ejemplo n.º 7
0
    def on_mention(self, event):
        post = event["data"]["post"]
        post = json.loads(post)
        sender = event["data"]["sender_name"]
        msg = post["message"]
        channel_id = post["channel_id"]
        user_id = post["user_id"]
        channel_data = self.driver.channels.get_channel(channel_id)
        channel_name = channel_data["name"]

        for tag in self.tags:
            msg = msg.replace(tag, "")

        LOG.info("New mention at channel: " + channel_name)
        LOG.info(sender + " said: " + msg)

        self.handle_mention(msg, sender, channel_id)
Ejemplo n.º 8
0
 def update_precise(self, precise_config):
     """Continously try to download precise until successful"""
     precise_exe = None
     while not precise_exe:
         try:
             precise_exe = self.install_exe(precise_config['dist_url'])
         except TriggerReload:
             raise
         except Exception as e:
             LOG.error(
                 'Precise could not be downloaded({})'.format(repr(e)))
             if exists(self.install_destination):
                 precise_exe = self.install_destination
             else:
                 # Wait one minute before retrying
                 sleep(60)
     return precise_exe
Ejemplo n.º 9
0
 def get_intent(self, utterance):
     """ get best intent for utterance """
     start = time.time()
     self._response = None
     self.waiting = True
     self.bus.emit(
         Message("intent.service.intent.get", {"utterance": utterance},
                 context={
                     "destination": "intent_service",
                     "source": "intent_api"
                 }))
     while self.waiting and time.time() - start <= self.timeout:
         time.sleep(0.3)
     if time.time() - start > self.timeout:
         LOG.error("Intent Service timed out!")
         return None
     return self._response["intent"]
Ejemplo n.º 10
0
    def _connect_to_gui(self, msg):
        # Attempt to connect to the port
        gui_id = msg.data.get("gui_id")
        if not gui_id == self.gui_id:
            # Not us, ignore!
            return

        # Create the websocket for GUI communications
        port = msg.data.get("port")
        if port:
            LOG.info("Connecting GUI on " + str(port))
            self.gui_ws = get_websocket(host=self.mycroft_ip,
                                        port=port,
                                        route="/gui")
            self.gui_ws.on("open", self.on_open)
            self.gui_ws.on("message", self.on_gui_message)
            self.gui_ws.run_in_thread()
Ejemplo n.º 11
0
    def handle_fallback(self, message):
        utt = message.data.get('utterance')
        LOG.debug(self.engine.name + " fallback attempt: " + utt)

        if not self.finished_training_event.is_set():
            LOG.debug('Waiting for training to finish...')
            self.finished_training_event.wait()

        data = self.engine.calc_intent(utt)

        if data["conf"] < 0.5:
            return False

        self.make_active()

        self.emitter.emit(message.reply(data["name"], data=data))
        return True
Ejemplo n.º 12
0
    def create_hotword_engines(self):
        LOG.info("creating hotword engines")
        hot_words = self.config_core.get("hotwords", {})
        for word in hot_words:
            data = hot_words[word]
            if word == self.wakeup_recognizer.key_phrase \
                    or not data.get("active", True):
                continue
            sound = data.get("sound")
            utterance = data.get("utterance")
            listen = data.get("listen", False)
            engine = HotWordFactory.create_hotword(word, lang=self.lang)

            self.hotword_engines[word] = {
                "engine": engine,
                "sound": sound,
                "utterance": utterance,
                "listen": listen
            }
Ejemplo n.º 13
0
 def handle_send(self, message):
     # send message to client
     msg = message.data.get("payload")
     is_file = message.data.get("isBinary")
     peer = message.data.get("peer")
     if is_file:
         # TODO send file
         pass
     elif peer in self.clients:
         # send message to client
         client = self.clients[peer]
         payload = Message.serialize(msg)
         client.sendMessage(payload, False)
     else:
         LOG.error("That client is not connected")
         self.mycroft_send("hive.client.send.error", {
             "error": "That client is not connected",
             "peer": peer
         }, message.context)
Ejemplo n.º 14
0
 def __init__(self, key_phrase="hey mycroft", config=None, lang="en-us"):
     super().__init__(key_phrase, config, lang)
     # Hotword module imports
     from snowboydecoder import HotwordDetector
     # Hotword module config
     module = self.config.get("module")
     if module != "snowboy":
         LOG.warning(module + " module does not match with Hotword class "
                              "snowboy")
     # Hotword params
     models = self.config.get("models", {})
     paths = []
     for key in models:
         paths.append(models[key])
     sensitivity = self.config.get("sensitivity", 0.5)
     self.snowboy = HotwordDetector(paths,
                                    sensitivity=[sensitivity] * len(paths))
     self.lang = str(lang).lower()
     self.key_phrase = str(key_phrase).lower()
Ejemplo n.º 15
0
 def initialize():
     nonlocal instance, complete
     try:
         clazz = HotWordFactory.CLASSES[module]
         instance = clazz(hotword, config, lang=lang)
     except TriggerReload:
         complete.set()
         sleep(0.5)
         loop.reload()
     except NoModelAvailable:
         LOG.warning('Could not found find model for {} on {}.'.format(
             hotword, module
         ))
         instance = None
     except Exception:
         LOG.exception(
             'Could not create hotword. Falling back to default.')
         instance = None
     complete.set()
Ejemplo n.º 16
0
def create_self_signed_cert(cert_dir, name="jarbas"):
    """
    If name.crt and name.key don't exist in cert_dir, create a new
    self-signed cert and key pair and write them into that directory.
    """
    if crypto is None:
        LOG.error("run pip install pyopenssl")
        raise ImportError
    CERT_FILE = name + ".crt"
    KEY_FILE = name + ".key"
    cert_path = join(cert_dir, CERT_FILE)
    key_path = join(cert_dir, KEY_FILE)

    if not exists(join(cert_dir, CERT_FILE)) \
            or not exists(join(cert_dir, KEY_FILE)):
        # create a key pair
        k = crypto.PKey()
        k.generate_key(crypto.TYPE_RSA, 1024)

        # create a self-signed cert
        cert = crypto.X509()
        cert.get_subject().C = "PT"
        cert.get_subject().ST = "Europe"
        cert.get_subject().L = "Mountains"
        cert.get_subject().O = "Jarbas AI"
        cert.get_subject().OU = "Powered by Mycroft-Core"
        cert.get_subject().CN = gethostname()
        cert.set_serial_number(random.randint(0, 2000))
        cert.gmtime_adj_notBefore(0)
        cert.gmtime_adj_notAfter(10 * 365 * 24 * 60 * 60)
        cert.set_issuer(cert.get_subject())
        cert.set_pubkey(k)
        # TODO don't use sha1
        cert.sign(k, 'sha1')
        if not exists(cert_dir):
            makedirs(cert_dir)
        open(cert_path,
             "wt").write(crypto.dump_certificate(crypto.FILETYPE_PEM, cert))
        open(join(cert_dir, KEY_FILE),
             "wt").write(crypto.dump_privatekey(crypto.FILETYPE_PEM, k))

    return cert_path, key_path
Ejemplo n.º 17
0
    def run(self):
        """Thread main loop. Get audio and extra data from queue and play.

        The queue messages is a tuple containing
        snd_type: 'mp3' or 'wav' telling the loop what format the data is in
        data: path to temporary audio data
        videmes: list of visemes to display while playing
        listen: if listening should be triggered at the end of the sentence.

        Playback of audio is started and the visemes are sent over the bus
        the loop then wait for the playback process to finish before starting
        checking the next position in queue.

        If the queue is empty the tts.end_audio() is called possibly triggering
        listening.
        """
        while not self._terminated:
            try:
                (snd_type, data,
                 visemes, ident, listen) = self.queue.get(timeout=2)
                if not self._processing_queue:
                    self._processing_queue = True
                    self.tts.begin_audio()

                if snd_type == 'wav':
                    self.p = play_wav(data)
                elif snd_type == 'mp3':
                    self.p = play_mp3(data)

                self.p.communicate()
                self.p.wait()

                if self.queue.empty():
                    self.tts.end_audio()
                    self._processing_queue = False
            except Empty:
                pass
            except Exception as e:
                LOG.exception(e)
                if self._processing_queue:
                    self.tts.end_audio()
                    self._processing_queue = False
Ejemplo n.º 18
0
    def get_cli_input(self):
        while True:
            if self.waiting:
                sleep(0.3)
                continue
            if self.debug:
                LOG.debug("waiting for input")
            if self.color:
                line = input("\x1b[6;33;40m INPUT: \x1b[0m")
            else:
                line = input("INPUT:")
            self.say(line)

            msg = {"data": {"utterances": [line],
                            "lang": "en-us"},
                   "type": "recognizer_loop:utterance",
                   "context": {"source": self.client.peer,
                               "destination": "hive_mind",
                               "platform": platform}}
            self.send_to_hivemind_bus(msg)
            self.waiting = True
Ejemplo n.º 19
0
    def on_gui_message(self, payload):
        try:
            msg = json.loads(payload)
            if self.debug:
                LOG.debug("Msg: " + str(payload))
            msg_type = msg.get("type")
            if msg_type == "mycroft.session.set":
                skill = msg.get("namespace")
                self.skill = self.skill or skill
                data = msg.get("data")
                if skill not in self.vars:
                    self.vars[skill] = {}
                for d in data:
                    self.vars[skill][d] = data[d]
                self.on_new_gui_data(data)
            elif msg_type == "mycroft.session.list.insert":
                # Insert new namespace
                self.skill = msg['data'][0]['skill_id']
                self.loaded.insert(0, [self.skill, []])
            elif msg_type == "mycroft.gui.list.insert":
                # Insert a page in an existing namespace
                self.page = msg['data'][0]['url']
                pos = msg.get('position')
                # TODO sometimes throws IndexError: list index out of range
                # not invalid json, seems like either pos is out of range or
                # "mycroft.session.list.insert" message was missed
                # NOTE: only happened once with wiki skill, cant replicate
                self.loaded[0][1].insert(pos, self.page)
                #self.skill = self.loaded[0][0]
            elif msg_type == "mycroft.session.list.move":
                # Move the namespace at "pos" to the top of the stack
                pos = msg.get('from')
                self.loaded.insert(0, self.loaded.pop(pos))
            elif msg_type == "mycroft.session.list.remove":
                pos = msg.get('position')
                skill = msg.get("namespace")
                if self.skill == skill:
                    self.skill = None
                self.loaded.pop(pos)
            elif msg_type == "mycroft.events.triggered":
                # Switch selected page of namespace
                skill = msg['namespace']
                self.skill = self.skill or skill
                pos = msg['data']['number']
                for n in self.loaded:
                    if n[0] == skill:
                        # TODO sometimes pos throws
                        #  IndexError: list index out of range
                        # ocasionally happens with weather skill
                        # LOGS:
                        #   05:38:29.363 - __main__:on_gui_message:56 - DEBUG - Msg: {"type": "mycroft.events.triggered", "namespace": "mycroft-weather.mycroftai", "event_name": "page_gained_focus", "data": {"number": 1}}
                        #   05:38:29.364 - __main__:on_gui_message:90 - ERROR - list index out of range
                        self.page = n[1][pos]

            self._draw_buffer()
            self.on_message(msg)
        except Exception as e:
            if self.debug:
                LOG.exception(e)
                LOG.error("Invalid JSON: " + str(payload))
Ejemplo n.º 20
0
    def _skip_wake_word(self):
        """Check if told programatically to skip the wake word

        For example when we are in a dialog with the user.
        """
        # TODO: remove startListening signal check in 20.02
        if check_for_signal('startListening') or self._listen_triggered:
            return True

        # Pressing the Mark 1 button can start recording (unless
        # it is being used to mean 'stop' instead)
        if check_for_signal('buttonPress', 1):
            # give other processes time to consume this signal if
            # it was meant to be a 'stop'
            sleep(0.25)
            if check_for_signal('buttonPress'):
                # Signal is still here, assume it was intended to
                # begin recording
                LOG.debug("Button Pressed, wakeword not needed")
                return True

        return False
Ejemplo n.º 21
0
 def unregister_client(self,
                       client,
                       code=3078,
                       reason=u"unregister client request"):
     """
    Remove client from list of managed connections.
    """
     LOG.info("deregistering client: " + str(client.peer))
     if client.peer in self.clients.keys():
         client_data = self.clients[client.peer] or {}
         j, ip, sock_num = client.peer.split(":")
         context = {
             "user": client_data.get("names", ["unknown_user"])[0],
             "source": client.peer
         }
         self.bus.emit(
             Message("hive.client.disconnect", {
                 "reason": reason,
                 "ip": ip,
                 "sock": sock_num
             }, context))
         client.sendClose(code, reason)
         self.clients.pop(client.peer)
Ejemplo n.º 22
0
 async def event_handler(self, event):
     event = json.loads(event)
     event_type = event.get("event", "")
     if event_type == "hello":
         self.on_connect(event)
     elif event_type == "status_change":
         self.on_status_change(event)
     elif event_type == "typing":
         self.on_typing(event)
     elif event_type == "posted":
         self.on_message(event)
     elif event_type == "channel_viewed":
         self.on_viewed(event)
     elif event_type == "preferences_changed":
         self.on_preferences_changed(event)
     elif event_type == "post_deleted":
         self.on_post_deleted(event)
     elif event_type == "user_added":
         self.on_user_added(event)
     elif event_type == "user_removed":
         self.on_user_removed(event)
     else:
         LOG.debug(event)
Ejemplo n.º 23
0
    def _normalized_numbers(self, sentence):
        """normalized numbers to word equivalent.

        Args:
            sentence (str): setence to speak

        Returns:
            stf: normalized sentences to speak
        """
        try:
            from lingua_franca.format import pronounce_number
            numbers = re.findall(r'-?\d+', sentence)
            normalized_num = [
                (num, pronounce_number(int(num)))
                for num in numbers
            ]
            for num, norm_num in normalized_num:
                sentence = sentence.replace(num, norm_num, 1)
        except TypeError:
            LOG.exception("type error in mimic2_tts.py _normalized_numbers()")
        except ImportError:
            LOG.warning("lingua_franca not installed, can not normalize numbers")
        return sentence
Ejemplo n.º 24
0
    def activate_layer(self, layer_num):
        # error check
        if layer_num < 0 or layer_num > len(self.layers):
            LOG.error("invalid layer number")
            return False

        self.current_layer = layer_num

        # disable other layers
        self.disable()

        # TODO in here we should wait for all intents to be detached
        # sometimes detach intent from this step comes after register from next
        # is there some bus signal we can track?
        sleep(0.3)

        # enable layer
        LOG.info("Activating Layer " + str(layer_num))
        if layer_num < len(self.layers) and len(self.layers):
            for intent_name in self.layers[layer_num]:
                self.enable_intent(intent_name)
            return True
        return False
Ejemplo n.º 25
0
def find_input_device(device_name):
    """ Find audio input device by name.

        Arguments:
            device_name: device name or regex pattern to match

        Returns: device_index (int) or None if device wasn't found
    """
    LOG.info('Searching for input device: {}'.format(device_name))
    LOG.debug('Devices: ')
    pa = pyaudio.PyAudio()
    pattern = re.compile(device_name)
    for device_index in range(pa.get_device_count()):
        dev = pa.get_device_info_by_index(device_index)
        LOG.debug('   {}'.format(dev['name']))
        if dev['maxInputChannels'] > 0 and pattern.match(dev['name']):
            LOG.debug('    ^-- matched')
            return device_index
    return None
Ejemplo n.º 26
0
    def load_local(self, path):
        """
            Load local json file into self.

            Args:
                path (str): file to load
        """
        path = expanduser(path)
        if exists(path) and isfile(path):
            try:
                config = load_commented_json(path)
                for key in config:
                    self.__setitem__(key, config[key])

                LOG.debug("Configuration {} loaded".format(path))
            except Exception as e:
                LOG.error("Error loading configuration '{}'".format(path))
                LOG.error(repr(e))
        else:
            LOG.debug("Configuration '{}' not defined, skipping".format(path))
Ejemplo n.º 27
0
    def listen(self, source, bus, stream=None):
        """Listens for chunks of audio that Mycroft should perform STT on.

        This will listen continuously for a wake-up-word, then return the
        audio chunk containing the spoken phrase that comes immediately
        afterwards.

        Args:
            source (AudioSource):  Source producing the audio chunks
            bus (EventEmitter): Emitter for notifications of when recording
                                    begins and ends.
            stream (AudioStreamHandler): Stream target that will receive chunks
                                         of the utterance audio while it is
                                         being recorded

        Returns:
            AudioData: audio with the user's utterance, minus the wake-up-word
        """
        assert isinstance(source, AudioSource), "Source must be an AudioSource"

        #        bytes_per_sec = source.SAMPLE_RATE * source.SAMPLE_WIDTH
        sec_per_buffer = float(source.CHUNK) / source.SAMPLE_RATE

        # Every time a new 'listen()' request begins, reset the threshold
        # used for silence detection.  This is as good of a reset point as
        # any, as we expect the user and Mycroft to not be talking.
        # NOTE: adjust_for_ambient_noise() doc claims it will stop early if
        #       speech is detected, but there is no code to actually do that.
        self.adjust_for_ambient_noise(source, 1.0)

        LOG.debug("Waiting for wake word...")
        self._wait_until_wake_word(source, sec_per_buffer, bus)
        self._listen_triggered = False
        if self._stop_signaled:
            return

        LOG.debug("Recording...")
        bus.emit("recognizer_loop:record_begin")

        frame_data = self._record_phrase(source, sec_per_buffer, stream)
        audio_data = self._create_audio_data(frame_data, source)
        bus.emit("recognizer_loop:record_end")

        LOG.debug("Thinking...")

        return audio_data
Ejemplo n.º 28
0
 def get_mixer(self, control="Master"):
     if self._mixer is None:
         try:
             mixer = Mixer(control)
         except Exception as e:
             try:
                 mixer = Mixer(control)
             except Exception as e:
                 try:
                     if control != "Master":
                         LOG.warning("could not allocate requested mixer, "
                                     "falling back to 'Master'")
                         mixer = Mixer("Master")
                     else:
                         raise
                 except Exception as e:
                     LOG.error("Couldn't allocate mixer")
                     LOG.exception(e)
                     raise
         self._mixer = mixer
     return self.mixer
Ejemplo n.º 29
0
    def run(self):
        """Start and reload mic and STT handling threads as needed.

        Wait for KeyboardInterrupt and shutdown cleanly.
        """
        try:
            self.start_async()
        except Exception:
            LOG.exception('Starting producer/consumer threads for listener '
                          'failed.')
            return

        # Handle reload of consumer / producer if config changes
        while self.state.running:
            try:
                time.sleep(1)
            except KeyboardInterrupt as e:
                LOG.error(e)
                self.stop()
                raise  # Re-raise KeyboardInterrupt
            except Exception:
                LOG.exception('Exception in RecognizerLoop')
                raise
Ejemplo n.º 30
0
 def register_client(self, client, platform=None):
     """
    Add client to list of managed connections.
    """
     platform = platform or "unknown"
     LOG.info("registering client: " + str(client.peer))
     t, ip, sock = client.peer.split(":")
     # see if ip address is blacklisted
     if ip in self.ip_list and self.blacklist:
         LOG.warning("Blacklisted ip tried to connect: " + ip)
         self.unregister_client(client, reason=u"Blacklisted ip")
         return
     # see if ip address is whitelisted
     elif ip not in self.ip_list and not self.blacklist:
         LOG.warning("Unknown ip tried to connect: " + ip)
         #  if not whitelisted kick
         self.unregister_client(client, reason=u"Unknown ip")
         return
     self.clients[client.peer] = {
         "object": client,
         "status": "connected",
         "platform": platform
     }