Esempio n. 1
0
    def __insert_new_namespace(self, namespace, pages):
        """ Insert new namespace and pages.

        This first sends a message adding a new namespace at the
        highest priority (position 0 in the namespace stack)

        Args:
            namespace (str):  The skill namespace to create
            pages (str):      Pages to insert (name matches QML)
        """
        LOG.debug("Inserting new namespace")
        self.send({"type": "mycroft.session.list.insert",
                   "namespace": "mycroft.system.active_skills",
                   "position": 0,
                   "data": [{"skill_id": namespace}]
                   })

        # Load any already stored Data
        data = self.datastore.get(namespace, {})
        for key in data:
            msg = {"type": "mycroft.session.set",
                   "namespace": namespace,
                   "data": {key: data[key]}}
            self.send(msg)

        LOG.debug("Inserting new page")
        self.send({"type": "mycroft.gui.list.insert",
                   "namespace": namespace,
                   "position": 0,
                   "data": [{"url": p} for p in pages]
                   })
        # Make sure the local copy is updated
        self.loaded.insert(0, Namespace(namespace, pages))
Esempio n. 2
0
 def file_path(self):
     """
     Returns the path to the yml file associated with this configuration
     Returns: path to this configuration yml
     """
     file_path = join(self.path, self.name + ".yml")
     if not isfile(file_path):
         create_file(file_path)
         LOG.debug(f"New YAML created: {file_path}")
     return file_path
Esempio n. 3
0
    def on_gui_client_connected(self, message):
        # GUI has announced presence
        LOG.info('GUI HAS ANNOUNCED!')
        port = self.global_config["gui_websocket"]["base_port"]
        LOG.debug("on_gui_client_connected")
        gui_id = message.data.get("gui_id")

        LOG.debug("Heard announcement from gui_id: {}".format(gui_id))

        # Announce connection, the GUI should connect on it soon
        self.bus.emit(Message("mycroft.gui.port",
                              {"port": port,
                               "gui_id": gui_id}))
def get_coordinates(gps_loc: dict) -> (float, float):
    """
    Gets the latitude and longitude for the passed location
    :param gps_loc: dict of "city", "state", "country"
    :return: lat, lng float values
    """
    coordinates = Nominatim(user_agent="neon-ai")
    try:
        location = coordinates.geocode(gps_loc)
        LOG.debug(f"{location}")
        return location.latitude, location.longitude
    except Exception as x:
        LOG.error(x)
        return -1, -1
Esempio n. 5
0
 def _write_yaml_file(self):
     """
     Overwrites and/or updates the YML at the specified file_path.
     """
     try:
         with self.lock:
             tmp_filename = join(self.path, f".{self.name}.tmp")
             LOG.debug(f"tmp_filename={tmp_filename}")
             shutil.copy2(self.file_path, tmp_filename)
             with open(self.file_path, 'w+') as f:
                 self.parser.dump(self._content, f)
                 LOG.debug(f"YAML updated {self.name}")
             self._loaded = os.path.getmtime(self.file_path)
             self._pending_write = False
             self._disk_content_hash = hash(repr(self._content))
     except FileNotFoundError as x:
         LOG.error(f"Configuration file not found error: {x}")
Esempio n. 6
0
    def listen(self, source, stream):
        """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
            stream (AudioStreamHandler): Stream target that will receive chunks
                                         of the utterance audio while it is
                                         being recorded

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

        # If skipping wake words, just pass audio to our streaming STT
        # TODO: Check config updates?
        if self.loop.stt.can_stream and not self.use_wake_word:
            lang = self.loop.stt.lang
            self.loop.emit("recognizer_loop:record_begin")
            self.loop.stt.stream.stream_start()
            frame_data = get_silence(source.SAMPLE_WIDTH)
            LOG.debug("Stream starting!")
            # event set in OPM
            while not self.loop.stt.transcript_ready.is_set():
                # Pass audio until STT tells us to stop (this is called again immediately)
                chunk = self.record_sound_chunk(source)
                if not is_speaking():
                    # Filter out Neon speech
                    self.loop.stt.stream.stream_chunk(chunk)
                    frame_data += chunk
            LOG.debug("stream ended!")
            audio_data = self._create_audio_data(frame_data, source)
            self.loop.emit("recognizer_loop:record_end")
        # If using wake words, wait until the wake_word is detected and then record the following phrase
        else:
            audio_data, lang = super().listen(source, stream)
        # one of the default plugins saves the speech to file and adds "filename" to context
        audio_data, context = self.audio_consumers.transform(audio_data)
        context["lang"] = lang
        return audio_data, context
Esempio n. 7
0
 def check_for_updates(self) -> dict:
     """
     Reloads updated configuration from disk. Used to reload changes when other instances modify a configuration
     Returns:Updated configuration.content
     """
     new_content = self._load_yaml_file()
     if new_content:
         LOG.debug(f"{self.name} Checked for Updates")
         self._content = new_content
     else:
         LOG.error("new_content is empty!!")
         new_content = self._load_yaml_file()
         if new_content:
             LOG.debug("second attempt success")
             self._content = new_content
         else:
             LOG.error("second attempt failed")
     return self._content
Esempio n. 8
0
    def remove_namespace(self, namespace):
        """ Remove namespace.

        Args:
            namespace (str): namespace to remove
        """
        index = self.__find_namespace(namespace)
        if index is None:
            return
        else:
            LOG.debug("Removing namespace {} at {}".format(namespace, index))
            self.send({"type": "mycroft.session.list.remove",
                       "namespace": "mycroft.system.active_skills",
                       "position": index,
                       "items_number": 1
                       })
            # Remove namespace from loaded namespaces
            self.loaded.pop(index)
Esempio n. 9
0
    def __remove_page(self, namespace, pos):
        """ Delete page.

        Args:
            namespace (str): Namespace to remove from
            pos (int):      Page position to remove
        """
        LOG.debug("Deleting {} from {}".format(pos, namespace))
        self.send({"type": "mycroft.gui.list.remove",
                   "namespace": namespace,
                   "position": pos,
                   "items_number": 1
                   })
        # Remove the page from the local reprensentation as well.
        self.loaded[0].pages.pop(pos)
        # Add a check to return any display to idle from position 0
        if (pos == 0 and len(self.loaded[0].pages) == 0):
            self.bus.emit(Message("mycroft.device.show.idle"))
Esempio n. 10
0
    def __switch_page(self, namespace, pages):
        """ Switch page to an already loaded page.

        Args:
            pages (list): pages (str) to switch to
            namespace (str):  skill namespace
        """
        try:
            num = self.loaded[0].pages.index(pages[0])
        except Exception as e:
            LOG.exception(repr(e))
            num = 0

        LOG.debug('Switching to already loaded page at '
                  'index {} in namespace {}'.format(num, namespace))
        self.send({"type": "mycroft.events.triggered",
                   "namespace": namespace,
                   "event_name": "page_gained_focus",
                   "data": {"number": num}})
Esempio n. 11
0
    def __move_namespace(self, from_pos, to_pos):
        """ Move an existing namespace to a new position in the stack.

        Args:
            from_pos (int): Position in the stack to move from
            to_pos (int): Position to move to
        """
        LOG.debug("Activating existing namespace")
        # Seems like the namespace is moved to the top automatically when
        # a page change is done. Deactivating this for now.
        if self.explicit_move:
            LOG.debug("move {} to {}".format(from_pos, to_pos))
            self.send({"type": "mycroft.session.list.move",
                       "namespace": "mycroft.system.active_skills",
                       "from": from_pos, "to": to_pos,
                       "items_number": 1})
        # Move the local representation of the skill from current
        # position to position 0.
        self.loaded.insert(to_pos, self.loaded.pop(from_pos))
Esempio n. 12
0
    def __insert_pages(self, namespace, pages):
        """ Insert pages into the namespace

        Args:
            namespace (str): Namespace to add to
            pages (list):    Pages (str) to insert
        """
        LOG.debug("Inserting new pages")
        if not isinstance(pages, list):
            raise ValueError('Argument must be list of pages')

        self.send({"type": "mycroft.gui.list.insert",
                   "namespace": namespace,
                   "position": len(self.loaded[0].pages),
                   "data": [{"url": p} for p in pages]
                   })
        # Insert the pages into local reprensentation as well.
        updated = Namespace(self.loaded[0].name, self.loaded[0].pages + pages)
        self.loaded[0] = updated
Esempio n. 13
0
    def show(self, namespace, page, index):
        """ Show a page and load it as needed.

        Args:
            page (str or list): page(s) to show
            namespace (str):  skill namespace
            index (int): ??? TODO: Unused in code ???

        TODO: - Update sync to match.
              - Separate into multiple functions/methods
        """

        LOG.debug("GUIConnection activating: " + namespace)
        pages = page if isinstance(page, list) else [page]

        # find namespace among loaded namespaces
        try:
            index = self.__find_namespace(namespace)
            if index is None:
                # This namespace doesn't exist, insert them first so they're
                # shown.
                self.__insert_new_namespace(namespace, pages)
                return
            else:  # Namespace exists
                if index > 0:
                    # Namespace is inactive, activate it by moving it to
                    # position 0
                    self.__move_namespace(index, 0)

                # Find if any new pages needs to be inserted
                new_pages = [p for p in pages if p not in self.loaded[0].pages]
                if new_pages:
                    self.__insert_pages(namespace, new_pages)
                else:
                    # No new pages, just switch
                    self.__switch_page(namespace, pages)
        except Exception as e:
            LOG.exception(repr(e))
def get_location(lat, lng) -> (str, str, str, str):
    """
    Gets location name values for the passed coordinates.
    Note that some coordinates do not have a city, but may have a county.
    :param lat: latitude
    :param lng: longitude
    :return: city, county, state, country
    """
    address = Nominatim(user_agent="neon-ai")
    location = address.reverse([lat, lng], language="en-US")
    LOG.debug(f"{location}")
    LOG.debug(f"{location.raw}")
    LOG.debug(f"{location.raw.get('address')}")
    city = location.raw.get('address').get('city') or location.raw.get('address').get('town')
    county = location.raw.get('address').get('county')
    state = location.raw.get('address').get('state')
    country = location.raw.get('address').get('country')
    return city, county, state, country
Esempio n. 15
0
    def update_yaml_file(self,
                         header=None,
                         sub_header=None,
                         value="",
                         multiple=False,
                         final=False):
        """
        Called by class's children to update, create, or initiate a new parameter in the
        specified YAML file. Creates and updates headers, adds or overwrites preference elements,
        associates value to the created or existing field. Recursive if creating a new
        header-preference-value combo.
        :param multiple: true if more than one continuous write is coming
        :param header: string with the new or existing main header
        :param sub_header: new or existing subheader (sublist)
        :param value: any value that should be associated with the headers.
        :param final: true if this is the last change when skip_reload was true
        :return: pre-existing parameter if nothing to update or error if invalid yaml_type.
        """
        # with self.lock.acquire(30):
        self.check_reload()
        before_change = self._content

        LOG.debug(value)
        if header and sub_header:
            try:
                before_change[header][sub_header] = value
            except KeyError:
                before_change[header] = {sub_header: value}
                return
        elif header and not sub_header:
            try:
                before_change[header] = value
            except Exception as x:
                LOG.error(x)
        else:
            LOG.debug("No change needed")
            if not final:
                return

        if not multiple:
            self._write_yaml_file()
        else:
            LOG.debug("More than one change")
            self._pending_write = True