Beispiel #1
0
    def build_message(self, kind, utt, message, speaker=None):
        """
        Build a message for user input or neon response
        :param kind: "neon speak" or "execute"
        :param utt: string to emit
        :param message: incoming message object
        :param speaker: speaker data dictionary
        :return: Message object
        """
        LOG.debug(speaker)

        default_speech = self.preference_speech(message)
        # Override user preference for all script responses
        if not speaker:
            speaker = {"name": "Neon",
                       "language": default_speech["tts_language"],
                       "gender": default_speech["tts_gender"],
                       "voice": default_speech["neon_voice"],
                       "override_user": True}
        elif speaker and speaker.get("language"):
            speaker["override_user"] = True
        else:
            speaker = None

        LOG.debug(f"data={message.data}")
        # LOG.debug(f"context={message.context}")

        emit_response = False
        if kind == "skill_data":
            emit_response = True
            kind = "execute"

        try:
            if kind == "execute":
                # This is picked up in the intent handler
                return message.reply("skills:execute.utterance", {
                    "utterances": [utt.lower()],
                    "lang": message.data.get("lang", "en-US"),
                    "session": None,
                    "ident": None,
                    "speaker": speaker
                }, {
                    "neon_should_respond": True,
                    "cc_data": {"request": utt,
                                "emit_response": emit_response,
                                "execute_from_script": True
                                }
                })
            elif kind == "neon speak":
                added_context = {"cc_data": message.context.get("cc_data", {})}
                added_context["cc_data"]["request"] = utt

                return message.reply("speak", {"lang": message.data.get("lang", "en-US"),
                                               "speaker": speaker
                                               }, added_context)
        except Exception as x:
            LOG.error(x)
 def __init__(self):
     super().__init__()
     try:
         from langdetect import detect, detect_langs
     except ImportError:
         LOG.error("Run pip install langdetect")
         raise
     self._detect = detect
     self._detect_prob = detect_langs
Beispiel #3
0
 def async_volume_handler(self, vol):
     LOG.error("ASYNC SET VOL PASSED IN %s" % (vol, ))
     if vol > 1.0:
         vol = vol / 10
     self.current_volume = vol
     LOG.error("ASYNC SET VOL TO %s" % (self.current_volume, ))
     # notify anybody listening on the bus who cares
     self.bus.emit(
         Message("hardware.volume", {"volume": self.current_volume},
                 context={"source": ["enclosure"]}))
 def tearDownClass(cls) -> None:
     super(TestAPIMethods, cls).tearDownClass()
     cls.messagebus.shutdown()
     cls.speech_thread.terminate()
     try:
         if cls.speech_thread.is_alive():
             LOG.error("Bus still alive")
             cls.speech_thread.kill()
     except Exception as e:
         LOG.error(e)
Beispiel #5
0
 def show_settings_gui(self):
     """
     Function to update and
     :return:
     """
     try:
         # TODO: Conditionalize register, only needs to happen once but only after skill init DM
         self.gui.register_settings()
         self.gui.show_settings()
     except Exception as e:
         LOG.error(e)
Beispiel #6
0
 def _confirmation_timeout(self, message):
     user = message.data.get("user", "local")
     try:
         if user in self.actions_to_confirm.keys():
             removed = self.actions_to_confirm.pop(user)
             LOG.info(f"confirmation timed out ({time.time()}): {removed}")
     except Exception as e:
         # Catches if the item was already popped
         LOG.error(e)
     if len(self.actions_to_confirm.keys()) == 0:
         self.reload_skill = True
Beispiel #7
0
    def __init__(self, name=None, bus=None, use_settings=True):
        self.user_config = get_neon_user_config()
        self.local_config = get_neon_local_config()

        self._ngi_settings: Optional[NGIConfig] = None

        super(NeonSkill, self).__init__(name, bus, use_settings)
        self.cache_loc = os.path.expanduser(self.local_config.get('dirVars', {}).get('cacheDir') or
                                            "~/.local/share/neon/cache")
        self.lru_cache = LRUCache()

        # TODO: Depreciate these references, signal use is discouraged DM
        self.create_signal = create_signal
        self.check_for_signal = check_for_signal

        self.sys_tz = gettz()
        self.gui_enabled = self.local_config.get("prefFlags", {}).get("guiEvents", False)

        # if use_settings:
        #     self.settings = {}
        #     self._initial_settings = None
        #     self.init_settings()
        # else:
        #     LOG.error(f"{name} Skill requested no settings!")
        #     self.settings = None

        self.scheduled_repeats = []

        # Server-specific imports and timeout setting
        # A server is a device that hosts the core and skills to serve clients,
        # but that a user will not interact with directly.
        # A server will likely serve multiple users and devices concurrently.
        if self.local_config.get("devVars", {}).get("devType", "generic") == "server":
            self.server = True
            self.default_intent_timeout = 90
        else:
            self.server = False
            self.default_intent_timeout = 60

        self.neon_core = True  # TODO: This should be depreciated DM
        self.actions_to_confirm = dict()

        self.skill_mode = self.user_config.content.get('response_mode', {}).get('speed_mode') or DEFAULT_SPEED_MODE
        self.extension_time = SPEED_MODE_EXTENSION_TIME.get(self.skill_mode)

        try:
            # Lang support
            self.language_config = get_neon_lang_config()
            self.lang_detector = DetectorFactory.create()  # Default fastlang
            self.translator = TranslatorFactory.create()  # Default Amazon
        except Exception as e:
            LOG.error(e)
            self.language_config, self.language_detector, self.translator = None, None, None
Beispiel #8
0
def find_neon_aws_keys(base_path: str = "~/") -> dict:
    """
    Searches standard locations for AWS credentials
    Args:
        base_path: Base directory to check in addition to XDG directories (default ~/)
    Returns:
        dict containing 'aws_access_key_id' and 'aws_secret_access_key'
    """
    path_to_check = os.path.expanduser(base_path)
    csv_paths = (path_to_check, os.path.join(path_to_check, "accessKeys.csv"))
    sys_path = os.path.expanduser("~/.aws/credentials")
    json_path = os.path.expanduser("~/.local/share/neon/aws.json")

    amazon_creds = None
    for path in csv_paths:
        if os.path.isfile(path):
            try:
                with open(path, "r") as f:
                    aws_id, aws_key = f.readlines()[1].rstrip('\n').split(
                        ',', 1)
                    amazon_creds = {
                        "aws_access_key_id": aws_id,
                        "aws_secret_access_key": aws_key
                    }

            except Exception as e:
                LOG.error(e)
                LOG.error(path)

    if not amazon_creds:
        if os.path.isfile(json_path):
            with open(json_path, "r") as f:
                amazon_creds = json.load(f)
        elif os.path.isfile(sys_path):
            with open(sys_path, "r") as f:
                for line in f.read().split("\n"):
                    if line.startswith("aws_access_key_id"):
                        aws_id = line.split("=", 1)[1].strip()
                    elif line.startswith("aws_secret_access_key"):
                        aws_key = line.split("=", 1)[1].strip()
            amazon_creds = {
                "aws_access_key_id": aws_id,
                "aws_secret_access_key": aws_key
            }

    if not amazon_creds:
        raise FileNotFoundError(
            f"No aws credentials found in default locations or path: {path_to_check}"
        )
    return amazon_creds
Beispiel #9
0
 def _emit_utterance_to_skills(self, message_to_emit: Message) -> bool:
     """
     Emits a message containing a user utterance to skills for intent
     processing and checks that it is received by the skills module.
     :param message_to_emit: utterance message to send
     :return: True if skills module received input, else False
     """
     # Emit single intent request
     ident = message_to_emit.context['ident']
     resp = self.bus.wait_for_response(message_to_emit, timeout=10)
     if not resp:
         LOG.error(f"Skills didn't handle {ident}!")
         return False
     return True
Beispiel #10
0
    def _init_settings(self):
        """
        Initializes yml-based skill config settings, updating from default dict as necessary for added parameters
        """
        # TODO: This should just use the underlying Mycroft methods DM
        super()._init_settings()
        if os.path.isfile(os.path.join(self.root_dir, "settingsmeta.yml")):
            skill_meta = NGIConfig("settingsmeta", self.root_dir).content
        elif os.path.isfile(os.path.join(self.root_dir, "settingsmeta.json")):
            with open(os.path.join(self.root_dir, "settingsmeta.json")) as f:
                skill_meta = json.load(f)
        else:
            skill_meta = None

        # Load defaults from settingsmeta
        default = {}
        if skill_meta:
            # LOG.info(skill_meta)
            LOG.info(skill_meta["skillMetadata"]["sections"])
            for section in skill_meta["skillMetadata"]["sections"]:
                for pref in section.get("fields", []):
                    if not pref.get("name"):
                        LOG.debug(f"non-data skill meta: {pref}")
                    else:
                        if pref.get("value") == "true":
                            value = True
                        elif pref.get("value") == "false":
                            value = False
                        elif isinstance(pref.get("value"), CommentedMap):
                            value = dict(pref.get("value"))
                        else:
                            value = pref.get("value")
                        default[pref["name"]] = value

        # Load or init configuration
        self._ngi_settings = NGIConfig(self.name, self.settings_write_path)

        # Load any new or updated keys
        try:
            LOG.debug(self._ngi_settings.content)
            LOG.debug(default)
            if self._ngi_settings.content and len(self._ngi_settings.content.keys()) > 0 and len(default.keys()) > 0:
                self._ngi_settings.make_equal_by_keys(default, recursive=False)
            elif len(default.keys()) > 0:
                LOG.info("No settings to load, use default")
                self._ngi_settings.populate(default)
        except Exception as e:
            LOG.error(e)
            self._ngi_settings.populate(default)
Beispiel #11
0
    def request_check_timeout(self, time_wait, intent_to_check):
        LOG.info("request received")
        LOG.info(time_wait)
        LOG.info(len(intent_to_check))
        try:
            if isinstance(intent_to_check, str):
                intent_to_check = [intent_to_check]

            for intent in intent_to_check:
                data = {'time_out': time_wait,
                        'intent_to_check': f"{self.skill_id}:{intent}"}
                LOG.debug(f"DM: Set Timeout: {data}")
                self.bus.emit(Message("set_timeout", data))
        except Exception as x:
            LOG.error(x)
Beispiel #12
0
    def run(self):
        LOG.debug("chase thread started")
        chase_ctr = 0
        while not self.exit_flag:
            chase_ctr += 1
            LOG.error("chase thread %s" % (chase_ctr, ))
            for x in range(0, 10):
                self.led_obj.set_led(x, self.fgnd_col)
                time.sleep(self.delay)
                self.led_obj.set_led(x, self.bkgnd_col)
            if chase_ctr > 10:
                self.exit_flag = True

        LOG.debug("chase thread stopped")
        self.led_obj.fill((0, 0, 0))
Beispiel #13
0
    def handle_audio_input(self, message):
        """
        Handler for `neon.audio_input`.
        Handles remote audio input to Neon and replies with confirmation
        :param message: Message associated with request
        """

        def build_context(msg: Message):
            ctx: dict = message.context
            defaults = {'client_name': 'mycroft_listener',
                        'client': 'api',
                        'source': 'speech_api',
                        'ident': time(),
                        'username': self.user_config["user"]["username"] or
                        "local",
                        'user_profiles': [self.user_config.content]}
            ctx = {**defaults, **ctx, 'destination': ['skills'],
                   'timing': {'start': msg.data.get('time'),
                              'transcribed': time()}}
            return ctx

        ident = message.context.get("ident") or "neon.audio_input.response"
        LOG.info(f"Handling audio input: {ident}")
        if message.data.get("audio_data"):
            wav_file_path = self._write_encoded_file(
                message.data.pop("audio_data"))
        else:
            wav_file_path = message.data.get("audio_file")
        lang = message.data.get("lang")
        try:
            _, parser_data, transcriptions = \
                self._get_stt_from_file(wav_file_path, lang)
            message.context["audio_parser_data"] = parser_data
            context = build_context(message)
            data = {
                "utterances": transcriptions,
                "lang": message.data.get("lang", "en-us")
            }
            handled = self._emit_utterance_to_skills(Message(
                'recognizer_loop:utterance', data, context))
            self.bus.emit(message.reply(ident,
                                        data={"parser_data": parser_data,
                                              "transcripts": transcriptions,
                                              "skills_recv": handled}))
        except Exception as e:
            LOG.error(e)
            self.bus.emit(message.reply(ident, data={"error": repr(e)}))
 def create(module=None):
     module = module or "fastlang"
     config = get_neon_lang_config()
     module = module or config.get("detection_module", "fastlang")
     try:
         clazz = DetectorFactory.CLASSES.get(module)
         return clazz()
     except Exception as e:
         # The translate backend failed to start. Report it and fall back to
         # default.
         LOG.exception(
             'The selected language detector backend could not be loaded, '
             'falling back to default...')
         LOG.error(e)
         if module != 'fastlang':
             return FastLangDetector()
         else:
             raise
def clean_quotes(raw_utt: str) -> str:
    """
    Method for stripping quotes from fully quoted strings in different languages
    :param raw_utt: Input string to be cleaned
    :return: string with all paired quote characters removed
    """
    if not raw_utt:
        raise ValueError("Expected a string and got None")
    if not isinstance(raw_utt, str):
        raise TypeError(f"{raw_utt} is not a string!")
    chars_to_remove = ['“', '"', '«', u'\u201d', u'\u00bb', u'\u201e', '「', '」', u'u\xa0', u'\u00a0']
    raw_utt = raw_utt.strip()
    utt = raw_utt
    trailing_punctuation = False
    if utt.endswith("."):
        trailing_punctuation = True
        utt = utt.rstrip(".")
    quotes_cleaned = False
    try:
        # Checks if utterance starts AND ends with some form of quotations and removes them accordingly
        while (utt.startswith('“') or utt.startswith(u'\u201d') or utt.startswith('"') or utt.startswith('«')
               or utt.startswith(u'\u00bb') or utt.startswith(u'\u201e') or utt.startswith('「') or
               utt.startswith(u'u\xa0') or utt.startswith(u'\u00a0')) and \
                (utt.endswith('“') or utt.endswith(u'\u201d') or utt.endswith('"') or utt.endswith(u'\u00bb') or
                 utt.endswith(u'\u201e') or utt.endswith('」') or utt.endswith(u'u\xa0') or
                 utt.endswith(u'\u00a0') or utt.endswith('»')):
            quotes_cleaned = True
            removed_left, removed_right = False, False
            for c in chars_to_remove:
                if not removed_left and utt.startswith(c):
                    utt = utt[1:]
                    removed_left = True
                if not removed_right and utt.endswith(c):
                    utt = utt[:-1]
                    removed_right = True
        if quotes_cleaned:
            if trailing_punctuation:
                return f"{utt}."
            return utt
        else:
            return raw_utt
    except Exception as x:
        LOG.error(x)
        return raw_utt
    def handle_goodbye_intent(self, message):
        """
        Note: now the "reply" intents are deactivated,
              since the user specified the end of the skill
              by saying "goodbye"
        """

        # Remove any awaiting confirmation
        try:
            user = self.get_utterance_user(message)
            self.actions_to_confirm.pop(user)
        except Exception as e:
            LOG.error(e)

        self.disable_intent('CaffeineContentGoodbyeIntent')
        # self.disable_intent('CaffeineYesIDoIntent')
        # self.disable_intent('Caffeine_no_intent')
        # LOG.debug('3- Goodbye')
        self.speak_dialog("StayCaffeinated")
Beispiel #17
0
def find_neon_google_keys(base_path: str = "~/") -> dict:
    """
    Locates google json credentials and returns the parsed credentials as a dict
    Args:
        base_path: Base directory to check in addition to XDG directories (default ~/)
    Returns:
        dict Google json credential
    """
    path_to_check = os.path.expanduser(base_path)
    paths_to_check = (path_to_check,
                      os.path.join(path_to_check, "google.json"),
                      os.path.expanduser("~/.local/share/neon/google.json"))
    for path in paths_to_check:
        if os.path.isfile(path):
            try:
                with open(path, "r") as f:
                    credential = json.load(f)
                return credential
            except Exception as e:
                LOG.error(f"Invalid google credential found at: {path}")
                raise e
    raise FileNotFoundError(f"No google credentials found in default locations or path: {path_to_check}")
Beispiel #18
0
 def preference_skill(self, message=None) -> dict:
     """
     Returns the skill settings configuration
     Equivalent to self.settings for non-server
     :param message: Message associated with request
     :return: dict of skill preferences
     """
     nick = get_message_user(message) if message else None
     if self.server and nick:
         try:
             skill = self.skill_id
             LOG.info(f"Get server prefs for skill={skill}")
             user_overrides = message.context["nick_profiles"][nick]["skills"].get(self.skill_id, dict())
             LOG.debug(user_overrides)
             merged_settings = {**self.settings, **user_overrides}
             if user_overrides.keys() != merged_settings.keys():
                 LOG.info(f"New settings keys: user={nick}|skill={self.skill_id}|user={user_overrides}")
                 self.update_skill_settings(merged_settings, message)
             return merged_settings
         except Exception as e:
             LOG.error(e)
     return self.settings
Beispiel #19
0
    def get_utterance_user(self, message: Optional[Message]) -> str:
        """
        Gets the user associated with the given message. Returns default 'local' or 'server' if no user specified.
        Args:
            message: Message associated with request

        Returns:
            Username associated with the message or a default value of 'local' or 'server'.
        """
        if self.server:
            default_user = "******"
        else:
            default_user = self.preference_user(message).get("username", "local")
        if not message:
            return default_user

        try:
            return get_message_user(message) or default_user
        except Exception as e:
            LOG.error(e)
            # TODO: Depreciate this and fix underlying error DM
            return default_user
    def preference_unit(self, message=None) -> dict:
        """
        Returns the units dictionary that contains time, date, measure formatting preferences
        Equivalent to self.user_config["units"] for non-server use
        """
        try:
            nick = get_message_user(message) if message else None
            if self.server:
                if not message or not nick:
                    LOG.warning("No message given!")
                    return self.user_config['units']

                if message.context.get("nick_profiles"):
                    return message.context["nick_profiles"][nick]["units"]
                else:
                    LOG.error(
                        f"Unable to get user settings! message={message.data}")
            else:
                return self.user_config['units']
        except Exception as x:
            LOG.error(x)
        return {'time': 12, 'date': 'MDY', 'measure': 'imperial'}
Beispiel #21
0
def get_forecast(lat: Union[str, float],
                 lng: Union[str, float],
                 units: str = "metric",
                 **kwargs) -> dict:
    """
    Queries Open Weather Map for weather data at the specified location
    :param lat: latitude
    :param lng: longitude
    :param units: Temperature and Speed units "metric", "imperial", or "standard"
    :param kwargs:
      'api_key' - optional str api_key to use for query (None to force remote lookup)
      'language' - optional language param (default english)
    :return: dict weather data
    """
    api_key = kwargs.get("api_key", AUTH_CONFIG.get("owm", {}).get("api_key"))

    if api_key:
        query_params = {
            "lat": lat,
            "lon": lng,
            "units": units,
            "appid": api_key
        }
        resp = query_owm_api(
            f"http://api.openweathermap.org/data/2.5/onecall?{urllib.parse.urlencode(query_params)}"
        )
    else:
        query_params = {"lat": lat, "lon": lng, "units": units}
        resp = request_neon_api(NeonAPI.OPEN_WEATHER_MAP, query_params)

    data = json.loads(resp["content"])
    if data.get('cod'):
        data['cod'] = str(
            data['cod']
        )  # 400 is str, 401 is int; cast all to str for safe refs
        LOG.error(f"Error return: {data}")
        # TODO: Handle failures
    return data
Beispiel #22
0
    def preference_brands(self, message=None) -> dict:
        """
        Returns a brands dictionary for the user
        Equivalent to self.user_config["speech"] for non-server use
        """
        try:
            nick = get_message_user(message) if message else None
            if self.server:
                if not message or not nick:
                    LOG.warning("No message given!")
                    return self.user_config['brands']

                if message.context.get("nick_profiles"):
                    return message.context["nick_profiles"][nick]["brands"]
                else:
                    LOG.error(f"Unable to get user settings! message={message.data}")
            else:
                return self.user_config['brands']
        except Exception as x:
            LOG.error(x)
        return {'ignored_brands': {},
                'favorite_brands': {},
                'specially_requested': {}}
Beispiel #23
0
def find_generic_keyfile(base_path: str, filename: str) -> str:
    """
    Locates a generic text keyfile
    Args:
        base_path: Base directory to check in addition to XDG directories (default ~/)
        filename: File basename to read
    Returns:
        str contents of located file
    """
    path_to_check = os.path.expanduser(base_path)
    paths_to_check = (path_to_check, os.path.join(path_to_check, filename),
                      os.path.expanduser(f"~/.local/share/neon/{filename}"))
    for path in paths_to_check:
        if os.path.isfile(path):
            try:
                with open(path, "r") as f:
                    credential = f.read().strip()
                return credential
            except Exception as e:
                LOG.error(f"Invalid credential found at: {path}")
                raise e
    raise FileNotFoundError(
        f"No credentials found in default locations or path: {path_to_check}")
 def preference_user(self, message=None) -> dict:
     """
     Returns the user dictionary with name, email
     Equivalent to self.user_config["user"] for non-server use
     """
     try:
         nick = get_message_user(message) if message else None
         if self.server:
             if not message or not nick:
                 LOG.warning("No message given!")
                 return self.user_config['user']
             if message.context.get("nick_profiles"):
                 return message.context["nick_profiles"][nick]["user"]
             else:
                 LOG.error(
                     f"Unable to get user settings! message={message.data}")
         else:
             return self.user_config['user']
     except Exception as x:
         LOG.error(x)
     return {
         'first_name': '',
         'middle_name': '',
         'last_name': '',
         'preferred_name': '',
         'full_name': '',
         'dob': 'YYYY/MM/DD',
         'age': '',
         'email': '',
         'username': '',
         'password': '',
         'picture': '',
         'about': '',
         'phone': '',
         'email_verified': False,
         'phone_verified': False
     }
    def send_email(self,
                   title,
                   body,
                   message=None,
                   email_addr=None,
                   attachments=None):
        """
        Send an email to the registered user's email.
        Email address priority: email_addr, user prefs from message, fallback to DeviceApi for Mycroft method

        Arguments:
            title (str): Title of email
            body  (str): HTML body of email. This supports
                         simple HTML like bold and italics
            email_addr (str): Optional email address to use
            attachments (dict): Optional dict of file names to Base64 encoded files
            message (Message): Optional message to get email from
        """
        if not email_addr and message:
            email_addr = self.preference_user(message).get("email")

        if email_addr:
            LOG.info("Send email via Neon Server")
            try:
                LOG.debug(f"body={body}")
                self.bus.emit(
                    Message(
                        "neon.send_email", {
                            "title": title,
                            "email": email_addr,
                            "body": body,
                            "attachments": attachments
                        }))
            except Exception as e:
                LOG.error(e)
        else:
            super().send_email(title, body)
Beispiel #26
0
def on_error(e='Unknown'):
    LOG.error('Enclosure failed: {}'.format(repr(e)))
Beispiel #27
0
def build_message(kind, utt, message, signal_to_check=None, speaker=None):
    """
    Build a message for user input or neon response
    :param kind: "neon speak" or "execute"
    :param utt: string to emit
    :param message: incoming message object
    :param signal_to_check: signal to check in speech
    :param speaker: speaker data dictionary
    :return: Message object
    """
    from copy import deepcopy

    from neon_utils import SKILL
    # utt = utt.strip('"')  This is done before calling build_message now

    # Use utt as default signal to check
    if not signal_to_check:
        signal_to_check = utt
    LOG.debug(speaker)

    default_speech = SKILL.preference_speech(message)
    # Override user preference for all script responses
    if not speaker:
        speaker = {
            "name": "Neon",
            "language": default_speech["tts_language"],
            "gender": default_speech["tts_gender"],
            "voice": default_speech["neon_voice"],
            "override_user": True
        }
    else:
        speaker["override_user"] = True

    LOG.debug(f"data={message.data}")
    LOG.debug(f"context={message.context}")

    emit_response = False
    if kind == "skill_data":
        emit_response = True
        kind = "execute"

    try:
        if kind in ("execute", "skill"):
            message.context["cc_data"] = message.context.get("cc_data", {})
            # This is picked up in the intent handler
            # return message.reply("skills:execute.utterance", {
            return message.reply(
                "recognizer_loop:utterance",
                {
                    "utterances": [utt.lower()],
                    "lang": message.data.get("lang", "en-US"),
                    "session": None,
                    "ident": None,
                    "speaker": speaker
                },
                {
                    # "mobile": message.context.get("mobile", False),
                    # "client": message.context.get("client", None),
                    # "flac_filename": message.context.get("flac_filename", ''),
                    # "nick_profiles": message.context.get("nick_profiles", {}),
                    "neon_should_respond": True,
                    "cc_data": {
                        "signal_to_check":
                        signal_to_check,
                        "request":
                        utt,
                        "emit_response":
                        emit_response,
                        # "Neon": True,
                        "execute_from_script":
                        True,
                        "audio_file":
                        message.context["cc_data"].get("audio_file", None),
                        "raw_utterance":
                        utt
                    }
                })
        elif kind == "neon speak":
            context = deepcopy(message.context)
            LOG.info(f"CONTEXT IS {context}")
            context["cc_data"] = context.get("cc_data", {})
            context["cc_data"]["signal_to_check"] = signal_to_check
            context["cc_data"]["request"] = utt

            return message.reply("speak", {
                "lang": message.data.get("lang", "en-US"),
                "speaker": speaker
            }, context)
    except Exception as x:
        LOG.error(x)
Beispiel #28
0
def on_error(e='Unknown'):
    LOG.error('Audio service failed to launch ({}).'.format(repr(e)))
Beispiel #29
0
def build_new_auth_config(key_path: str = "~/") -> dict:
    """
    Constructs a dict of authentication key data by locating credential files in the specified path
    :param key_path: path to locate key files (default locations checked in addition)
    :return: dict of located authentication keys
    """
    key_path = key_path or "~/"
    auth_config = dict()
    try:
        auth_config["github"] = {"token": find_neon_git_token(key_path)}
    except Exception as e:
        LOG.error(e)
    try:
        auth_config["amazon"] = find_neon_aws_keys(key_path)
    except Exception as e:
        LOG.error(e)
    try:
        auth_config["wolfram"] = {"app_id": find_neon_wolfram_key(key_path)}
    except Exception as e:
        LOG.error(e)
    try:
        auth_config["google"] = find_neon_google_keys(key_path)
    except Exception as e:
        LOG.error(e)
    try:
        auth_config["alpha_vantage"] = {
            "api_key": find_neon_alpha_vantage_key(key_path)
        }
    except Exception as e:
        LOG.error(e)
    try:
        auth_config["owm"] = {"api_key": find_neon_owm_key(key_path)}
    except Exception as e:
        LOG.error(e)

    return auth_config
def scrape_page_for_links(url: str) -> dict:
    """
    Scrapes the passed url for any links and returns a dictionary of link labels to URLs
    :param url: Web page to scrape
    :return: Lowercase names to links on page
    """
    import unicodedata
    available_links = {}
    retry_count = 0

    def _get_links(url):
        LOG.debug(url)
        if not str(url).startswith("http"):
            url = f"http://{url}"
        LOG.debug(url)
        html = requests.get(url, timeout=2.0).text
        soup = BeautifulSoup(html, 'lxml')
        # LOG.debug(html)
        # LOG.debug(soup)

        # Look through the page and find all anchor tags
        for i in soup.find_all("a", href=True):
            # LOG.debug(f"DM: found link: {i.text.rstrip()}")
            # LOG.debug(f"DM: found href: {i['href']}")

            if '://' not in i['href']:
                # Assume this is a relative address
                href = url + i['href'].lower()
            elif url.split('://')[1] in i['href']:
                href = i['href'].lower()
            else:
                href = None

            if href:
                available_links[unicodedata.normalize('NFKD', i.text.rstrip()
                                                      .replace(u'\u2013', '')
                                                      .replace(u'\u201d', '')
                                                      .replace(u'\u201c', '')
                                                      .replace('"', "")
                                                      .replace("'", "")
                                                      .replace("'", "")
                                                      .lower())] = href
                LOG.debug("found link: " + unicodedata.normalize("NFKD", i.text.rstrip().replace(u"\u2013", "")
                                                                 .replace(u"\u201d", "").replace(u"\u201c", "")
                                                                 .replace('"', "").replace("'", "")
                                                                 .replace("'", "").replace("\n", "").lower()))
                LOG.debug("found href: " + href)

        LOG.debug(available_links)

    try:
        _get_links(url)
    except ConnectTimeout:
        retry_count += 1
        if retry_count < 8:
            _get_links(url)
        else:
            raise ConnectTimeout
    except Exception as x:
        LOG.error(x)
        LOG.debug(available_links)
        raise ReferenceError
    return available_links