Ejemplo n.º 1
0
 def __init__(self, key_phrase="hey OwO", config=None, lang="en-us"):
     self.key_phrase = str(key_phrase).lower()
     # rough estimate 1 phoneme per 2 chars
     self.num_phonemes = len(key_phrase) / 2 + 1
     if config is None:
         config = Configuration.get().get("hot_words", {})
         config = config.get(self.key_phrase, {})
     self.config = config
     self.listener_config = Configuration.get().get("listener", {})
     self.lang = str(self.config.get("lang", lang)).lower()
Ejemplo n.º 2
0
    def __init__(self):
        self.bus = WebsocketClient()

        Configuration.init(self.bus)

        global_config = Configuration.get()
        self.lang = global_config['lang']
        self.config = global_config.get("enclosure")

        self.__init_serial()
        self.reader = EnclosureReader(self.serial, self.bus, self.lang)
        self.writer = EnclosureWriter(self.serial, self.bus)

        # Prepare to receive message when the Arduino responds to the
        # following "system.version"
        self.bus.on("enclosure.started", self.on_arduino_responded)
        self.arduino_responded = False
        # Send a message to the Arduino across the serial line asking
        # for a reply with version info.
        self.writer.write("system.version")
        # Start a 5 second timer.  If the serial port hasn't received
        # any acknowledgement of the "system.version" within those
        # 5 seconds, assume there is nothing on the other end (e.g.
        # we aren't running a Mark 1 with an Arduino)
        Timer(5, self.check_for_response).start()

        # Notifications from OwO-core
        self.bus.on("enclosure.notify.no_internet", self.on_no_internet)

        # initiates the web sockets on display manager
        # NOTE: this is a temporary place to connect the display manager
        init_display_manager_bus_connection()
Ejemplo n.º 3
0
def main():
    import tornado.options
    reset_sigint_handler()
    lock = Lock("service")
    tornado.options.parse_command_line()

    def reload_hook():
        """ Hook to release lock when autoreload is triggered. """
        lock.delete()

    autoreload.add_reload_hook(reload_hook)

    config = Configuration.get().get("websocket")

    host = config.get("host")
    port = config.get("port")
    route = config.get("route")
    validate_param(host, "websocket.host")
    validate_param(port, "websocket.port")
    validate_param(route, "websocket.route")

    routes = [(route, WebsocketEventHandler)]
    application = web.Application(routes, **settings)
    application.listen(port, host)
    create_daemon(ioloop.IOLoop.instance().start)

    wait_for_exit_signal()
Ejemplo n.º 4
0
    def __init__(self, bus, service):
        FallbackSkill.__init__(self)
        if not PadatiousService.instance:
            PadatiousService.instance = self

        self.config = Configuration.get()['padatious']
        self.service = service
        intent_cache = expanduser(self.config['intent_cache'])

        try:
            from padatious import IntentContainer
        except ImportError:
            LOG.error('Padatious not installed. Please re-run dev_setup.sh')
            try:
                call([
                    'notify-send', 'Padatious not installed',
                    'Please run build_host_setup and dev_setup again'
                ])
            except OSError:
                pass
            return

        self.container = IntentContainer(intent_cache)

        self.bus = bus
        self.bus.on('padatious:register_intent', self.register_intent)
        self.bus.on('padatious:register_entity', self.register_entity)
        self.bus.on('detach_intent', self.handle_detach_intent)
        self.bus.on('owo.skills.initialized', self.train)
        self.register_fallback(self.handle_fallback, 5)
        self.finished_training_event = Event()
        self.finished_initial_train = False

        self.train_delay = self.config['train_delay']
        self.train_time = get_time() + self.train_delay
Ejemplo n.º 5
0
def get(phrase, lang=None, context=None):
    """
    Looks up a resource file for the given phrase.  If no file
    is found, the requested phrase is returned as the string.
    This will use the default language for translations.

    Args:
        phrase (str): resource phrase to retrieve/translate
        lang (str): the language to use
        context (dict): values to be inserted into the string

    Returns:
        str: a randomized and/or translated version of the phrase
    """

    if not lang:
        from owo.configuration import Configuration
        lang = Configuration.get().get("lang")

    filename = "text/" + lang.lower() + "/" + phrase + ".dialog"
    template = resolve_resource_file(filename)
    if not template:
        LOG.debug("Resource file not found: " + filename)
        return phrase

    stache = MustacheDialogRenderer()
    stache.load_template_file("template", template)
    if not context:
        context = {}
    return stache.render("template", context)
Ejemplo n.º 6
0
 def __init__(self):
     config_core = Configuration.get()
     self.lang = str(self.init_language(config_core))
     config_stt = config_core.get("stt", {})
     self.config = config_stt.get(config_stt.get("module"), {})
     self.credential = self.config.get("credential", {})
     self.recognizer = Recognizer()
Ejemplo n.º 7
0
    def __init__(self, bus):
        self.config = Configuration.get().get('context', {})
        self.engine = IntentDeterminationEngine()

        # Dictionary for translating a skill id to a name
        self.skill_names = {}
        # Context related intializations
        self.context_keywords = self.config.get('keywords', [])
        self.context_max_frames = self.config.get('max_frames', 3)
        self.context_timeout = self.config.get('timeout', 2)
        self.context_greedy = self.config.get('greedy', False)
        self.context_manager = ContextManager(self.context_timeout)
        self.bus = bus
        self.bus.on('register_vocab', self.handle_register_vocab)
        self.bus.on('register_intent', self.handle_register_intent)
        self.bus.on('recognizer_loop:utterance', self.handle_utterance)
        self.bus.on('detach_intent', self.handle_detach_intent)
        self.bus.on('detach_skill', self.handle_detach_skill)
        # Context related handlers
        self.bus.on('add_context', self.handle_add_context)
        self.bus.on('remove_context', self.handle_remove_context)
        self.bus.on('clear_context', self.handle_clear_context)
        # Converse method
        self.bus.on('skill.converse.response', self.handle_converse_response)
        self.bus.on('owo.speech.recognition.unknown', self.reset_converse)
        self.bus.on('owo.skills.loaded', self.update_skill_name_dict)

        def add_active_skill_handler(message):
            self.add_active_skill(message.data['skill_id'])

        self.bus.on('active_skill_request', add_active_skill_handler)
        self.active_skills = []  # [skill_id , timestamp]
        self.converse_timeout = 5  # minutes to prune active_skills
Ejemplo n.º 8
0
    def run(self):
        """ Load skills and update periodically from disk and internet """

        self.remove_git_locks()
        self._connected_event.wait()
        has_loaded = False

        # check if skill updates are enabled
        update = Configuration.get()["skills"]["auto_update"]

        # Scan the file folder that contains Skills.  If a Skill is updated,
        # unload the existing version from memory and reload from the disk.
        while not self._stop_event.is_set():
            # Update skills once an hour if update is enabled
            if time.time() >= self.next_download and update:
                self.download_skills()

            # Look for recently changed skill(s) needing a reload
            # checking skills dir and getting all skills there
            skill_paths = glob(join(self.msm.skills_dir, '*/'))
            still_loading = False
            for skill_path in skill_paths:
                still_loading = (self._load_or_reload_skill(skill_path)
                                 or still_loading)
            if not has_loaded and not still_loading and len(skill_paths) > 0:
                has_loaded = True
                self.bus.emit(Message('owo.skills.initialized'))

            self._unload_removed(skill_paths)
            # Pause briefly before beginning next scan
            time.sleep(2)
Ejemplo n.º 9
0
    def __init__(self, wake_word_recognizer):

        self.config = Configuration.get()
        listener_config = self.config.get('listener')
        self.upload_url = listener_config['wake_word_upload']['url']
        self.upload_disabled = listener_config['wake_word_upload']['disable']
        self.wake_word_name = wake_word_recognizer.key_phrase

        self.overflow_exc = listener_config.get('overflow_exception', False)

        speech_recognition.Recognizer.__init__(self)
        self.wake_word_recognizer = wake_word_recognizer
        self.audio = pyaudio.PyAudio()
        self.multiplier = listener_config.get('multiplier')
        self.energy_ratio = listener_config.get('energy_ratio')
        # check the config for the flag to save wake words.

        self.save_utterances = listener_config.get('record_utterances', False)
        self.upload_lock = Lock()
        self.filenames_to_upload = []
        self.mic_level_file = os.path.join(get_ipc_directory(), "mic_level")
        self._stop_signaled = False

        # The maximum audio in seconds to keep for transcribing a phrase
        # The wake word must fit in this time
        num_phonemes = wake_word_recognizer.num_phonemes
        len_phoneme = listener_config.get('phoneme_duration', 120) / 1000.0
        self.TEST_WW_SEC = num_phonemes * len_phoneme
        self.SAVED_WW_SEC = max(3, self.TEST_WW_SEC)

        try:
            self.account_id = DeviceApi().get()['user']['uuid']
        except (requests.RequestException, AttributeError):
            self.account_id = '0'
Ejemplo n.º 10
0
    def __init__(self, bus, schedule_file='schedule.json'):
        """
            Create an event scheduler thread. Will send messages at a
            predetermined time to the registered targets.

            Args:
                bus:            OwO messagebus (owo.messagebus)
                schedule_file:  File to store pending events to on shutdown
        """
        super(EventScheduler, self).__init__()
        data_dir = expanduser(Configuration.get()['data_dir'])

        self.events = {}
        self.event_lock = Lock()

        self.bus = bus
        self.isRunning = True
        self.schedule_file = join(data_dir, schedule_file)
        if self.schedule_file:
            self.load()

        self.bus.on('owo.scheduler.schedule_event',
                    self.schedule_event_handler)
        self.bus.on('owo.scheduler.remove_event', self.remove_event_handler)
        self.bus.on('owo.scheduler.update_event', self.update_event_handler)
        self.bus.on('owo.scheduler.get_event', self.get_event_handler)
        self.start()
Ejemplo n.º 11
0
    def __init__(self, bus):
        super(SkillManager, self).__init__()
        self._stop_event = Event()
        self._connected_event = Event()

        self.loaded_skills = {}
        self.bus = bus
        self.enclosure = EnclosureAPI(bus)

        # Schedule install/update of default skill
        self.msm = self.create_msm()
        self.num_install_retries = 0

        self.update_interval = Configuration.get()['skills']['update_interval']
        self.update_interval = int(self.update_interval * 60 * MINUTES)
        self.dot_msm = join(self.msm.skills_dir, '.msm')
        if exists(self.dot_msm):
            self.next_download = os.path.getmtime(self.dot_msm) + \
                                 self.update_interval
        else:
            self.next_download = time.time() - 1

        # Conversation management
        bus.on('skill.converse.request', self.handle_converse_request)

        # Update on initial connection
        bus.on('owo.internet.connected', lambda x: self._connected_event.set())

        # Update upon request
        bus.on('skillmanager.update', self.schedule_now)
        bus.on('skillmanager.list', self.send_skill_list)
        bus.on('skillmanager.deactivate', self.deactivate_skill)
        bus.on('skillmanager.keep', self.deactivate_except)
        bus.on('skillmanager.activate', self.activate_skill)
Ejemplo n.º 12
0
 def validate_connection(self):
     config = Configuration.get().get("tts", {}).get("watson", {})
     user = config.get("user") or config.get("username")
     password = config.get("password")
     if user and password:
         return
     else:
         raise ValueError('user and/or password for IBM tts is not defined')
Ejemplo n.º 13
0
 def __init__(self, lang, config):
     super(BingTTS, self).__init__(lang, config, BingTTSValidator(self))
     self.type = 'wav'
     from bingtts import Translator
     self.config = Configuration.get().get("tts", {}).get("bing", {})
     api = self.config.get("api_key")
     self.bing = Translator(api)
     self.gender = self.config.get("gender", "Male")
     self.format = self.config.get("format", "riff-16khz-16bit-mono-pcm")
Ejemplo n.º 14
0
 def get():
     data_dir = expanduser(Configuration.get()['data_dir'])
     version_file = join(data_dir, 'version.json')
     if exists(version_file) and isfile(version_file):
         try:
             with open(version_file) as f:
                 return json.load(f)
         except Exception:
             LOG.error("Failed to load version from '%s'" % version_file)
     return {"coreVersion": None, "enclosureVersion": None}
Ejemplo n.º 15
0
    def __init__(self, path):
        self.path = path

        # Load the config, skipping the REMOTE_CONFIG since we are
        # getting the info needed to get to it!
        config = Configuration.get(
            [DEFAULT_CONFIG, SYSTEM_CONFIG, USER_CONFIG], cache=False)
        config_server = config.get("server")
        self.url = config_server.get("url")
        self.version = config_server.get("version")
        self.identity = IdentityManager.get()
Ejemplo n.º 16
0
def handle_speak(event):
    """
        Handle "speak" message
    """
    config = Configuration.get()
    Configuration.init(bus)
    global _last_stop_signal

    # Get conversation ID
    if event.context and 'ident' in event.context:
        ident = event.context['ident']
    else:
        ident = 'unknown'

    with lock:
        stopwatch = Stopwatch()
        stopwatch.start()
        utterance = event.data['utterance']
        if event.data.get('expect_response', False):
            # When expect_response is requested, the listener will be restarted
            # at the end of the next bit of spoken audio.
            bus.once('recognizer_loop:audio_output_end', _start_listener)

        # This is a bit of a hack for Picroft.  The analog audio on a Pi blocks
        # for 30 seconds fairly often, so we don't want to break on periods
        # (decreasing the chance of encountering the block).  But we will
        # keep the split for non-Picroft installs since it give user feedback
        # faster on longer phrases.
        #
        # TODO: Remove or make an option?  This is really a hack, anyway,
        # so we likely will want to get rid of this when not running on Mimic
        if (config.get('enclosure', {}).get('platform') != "picroft"
                and len(re.findall('<[^>]*>', utterance)) == 0):
            start = time.time()
            chunks = re.split(r'(?<!\w\.\w.)(?<![A-Z][a-z]\.)(?<=\.|\?)\s',
                              utterance)
            for chunk in chunks:
                try:
                    mute_and_speak(chunk, ident)
                except KeyboardInterrupt:
                    raise
                except Exception:
                    LOG.error('Error in mute_and_speak', exc_info=True)
                if (_last_stop_signal > start
                        or check_for_signal('buttonPress')):
                    break
        else:
            mute_and_speak(utterance, ident)

        stopwatch.stop()
    report_timing(ident, 'speech', stopwatch, {
        'utterance': utterance,
        'tts': tts.__class__.__name__
    })
Ejemplo n.º 17
0
    def create_hotword(cls,
                       hotword="hey OwO",
                       config=None,
                       lang="en-us",
                       loop=None):
        if not config:
            config = Configuration.get()['hotwords']
        config = config[hotword]

        module = config.get("module", "pocketsphinx")
        return cls.load_module(module, hotword, config, lang, loop) or \
            cls.load_module('pocketsphinx', hotword, config, lang, loop) or \
            cls.CLASSES['pocketsphinx']()
Ejemplo n.º 18
0
 def create_msm():
     config = Configuration.get()
     msm_config = config['skills']['msm']
     repo_config = msm_config['repo']
     data_dir = expanduser(config['data_dir'])
     skills_dir = join(data_dir, msm_config['directory'])
     repo_cache = join(data_dir, repo_config['cache'])
     platform = config['enclosure'].get('platform', 'default')
     return OwOSkillsManager(platform=platform,
                             skills_dir=skills_dir,
                             repo=SkillRepo(repo_cache, repo_config['url'],
                                            repo_config['branch']),
                             versioned=msm_config['versioned'])
Ejemplo n.º 19
0
    def get():
        """
        get the active session.

        :return: An active session
        """
        config = Configuration.get().get('session')

        with SessionManager.__lock:
            if (not SessionManager.__current_session
                    or SessionManager.__current_session.expired()):
                SessionManager.__current_session = Session(
                    str(uuid4()), expiration_seconds=config.get('ttl', 180))
                LOG.info("New Session Start: " +
                         SessionManager.__current_session.session_id)
            return SessionManager.__current_session
Ejemplo n.º 20
0
    def __init__(self, host=None, port=None, route=None, ssl=None):

        config = Configuration.get().get("websocket")
        host = host or config.get("host")
        port = port or config.get("port")
        route = route or config.get("route")
        ssl = ssl or config.get("ssl")
        validate_param(host, "websocket.host")
        validate_param(port, "websocket.port")
        validate_param(route, "websocket.route")

        self.url = WebsocketClient.build_url(host, port, route, ssl)
        self.emitter = EventEmitter()
        self.client = self.create_client()
        self.pool = ThreadPool(10)
        self.retry = 5
        self.connected_event = Event()
        self.started_running = False
Ejemplo n.º 21
0
    def __init__(self, name=None, bus=None):
        self.name = name or self.__class__.__name__
        # Get directory of skill
        self._dir = dirname(abspath(sys.modules[self.__module__].__file__))
        self.settings = SkillSettings(self._dir, self.name)

        self.bus = None
        self.bind(bus)
        self.config_core = Configuration.get()
        self.config = self.config_core.get(self.name) or {}
        self.dialog_renderer = None
        self.root_dir = None
        self.file_system = FileSystemAccess(join('skills', self.name))
        self.registered_intents = []
        self.log = LOG.create_logger(self.name)
        self.reload_skill = True  # allow reloading
        self.events = []
        self.scheduled_repeats = []
        self.skill_id = ''  # will be set from the path, so guaranteed unique
        self.voc_match_cache = {}
Ejemplo n.º 22
0
    def create():
        """
        Factory method to create a TTS engine based on configuration.

        The configuration file ``owo.conf`` contains a ``tts`` section with
        the name of a TTS module to be read by this method.

        "tts": {
            "module": <engine_name>
        }
        """
        config = Configuration.get()
        lang = config.get("lang", "en-us")
        tts_module = config.get('tts', {}).get('module', 'mimic')
        tts_config = config.get('tts', {}).get(tts_module, {})
        tts_lang = tts_config.get('lang', lang)
        clazz = TTSFactory.CLASSES.get(tts_module)
        tts = clazz(tts_lang, tts_config)
        tts.validator.validate()
        return tts
Ejemplo n.º 23
0
    def __init__(self, bus):
        """
            Args:
                bus: OwO messagebus
        """
        self.bus = bus
        self.config = Configuration.get().get("Audio")
        self.service_lock = Lock()

        self.default = None
        self.service = []
        self.current = None
        self.volume_is_low = False
        self.pulse = None
        self.pulse_quiet = None
        self.pulse_restore = None

        self.muted_sinks = []
        # Setup control of pulse audio
        self.setup_pulseaudio_handlers(self.config.get('pulseaudio'))
        bus.once('open', self.load_services_callback)
Ejemplo n.º 24
0
    def update_version(self):
        version = VersionManager.get()
        platform = "unknown"
        platform_build = ""

        # load just the local configs to get platform info
        config = Configuration.get([SYSTEM_CONFIG, USER_CONFIG], cache=False)
        if "enclosure" in config:
            platform = config.get("enclosure").get("platform", "unknown")
            platform_build = config.get("enclosure").get("platform_build", "")

        return self.request({
            "method": "PATCH",
            "path": "/" + self.identity.uuid,
            "json": {
                "coreVersion": version.get("coreVersion"),
                "platform": platform,
                "platform_build": platform_build,
                "enclosureVersion": version.get("enclosureVersion")
            }
        })
Ejemplo n.º 25
0
def default_timezone():
    """ Get the default timezone

    Based on user location settings location.timezone.code or
    the default system value if no setting exists.

    Returns:
        (datetime.tzinfo): Definition of the default timezone
    """
    try:
        # Obtain from user's configurated settings
        #   location.timezone.code (e.g. "America/Chicago")
        #   location.timezone.name (e.g. "Central Standard Time")
        #   location.timezone.offset (e.g. -21600000)
        from owo.configuration import Configuration
        config = Configuration.get()
        code = config["location"]["timezone"]["code"]

        return gettz(code)
    except Exception:
        # Just go with system default timezone
        return tzlocal()
Ejemplo n.º 26
0
    def activate(self, state, token):
        version = VersionManager.get()
        platform = "unknown"
        platform_build = ""

        # load just the local configs to get platform info
        config = Configuration.get([SYSTEM_CONFIG, USER_CONFIG], cache=False)
        if "enclosure" in config:
            platform = config.get("enclosure").get("platform", "unknown")
            platform_build = config.get("enclosure").get("platform_build", "")

        return self.request({
            "method": "POST",
            "path": "/activate",
            "json": {
                "state": state,
                "token": token,
                "coreVersion": version.get("coreVersion"),
                "platform": platform,
                "platform_build": platform_build,
                "enclosureVersion": version.get("enclosureVersion")
            }
        })
Ejemplo n.º 27
0
    def _load_config(self):
        """
            Load configuration parameters from configuration
        """
        config = Configuration.get()
        self.config_core = config
        self._config_hash = hash(str(config))
        self.lang = config.get('lang')
        self.config = config.get('listener')
        rate = self.config.get('sample_rate')
        device_index = self.config.get('device_index')

        self.microphone = MutableMicrophone(device_index,
                                            rate,
                                            mute=self.mute_calls > 0)
        # FIXME - channels are not been used
        self.microphone.CHANNELS = self.config.get('channels')
        self.wakeword_recognizer = self.create_wake_word_recognizer()
        # TODO - localization
        self.wakeup_recognizer = self.create_wakeup_recognizer()
        self.responsive_recognizer = ResponsiveRecognizer(
            self.wakeword_recognizer)
        self.state = RecognizerLoopState()
Ejemplo n.º 28
0
def init(messagebus):
    """ Start speech related handlers.

    Arguments:
        messagebus: Connection to the OwO messagebus
    """

    global bus
    global tts
    global tts_hash
    global config

    bus = messagebus
    Configuration.init(bus)
    config = Configuration.get()
    bus.on('owo.stop', handle_stop)
    bus.on('owo.audio.speech.stop', handle_stop)
    bus.on('speak', handle_speak)
    bus.on('owo.mic.listen', _start_listener)

    tts = TTSFactory.create()
    tts.init(bus)
    tts_hash = config.get('tts')
Ejemplo n.º 29
0
def create_echo_function(name, whitelist=None):
    from owo.configuration import Configuration
    blacklist = Configuration.get().get("ignore_logs")

    def echo(message):
        """Listen for messages and echo them for logging"""
        try:
            js_msg = json.loads(message)

            if whitelist and js_msg.get("type") not in whitelist:
                return

            if blacklist and js_msg.get("type") in blacklist:
                return

            if js_msg.get("type") == "registration":
                # do not log tokens from registration messages
                js_msg["data"]["token"] = None
                message = json.dumps(js_msg)
        except Exception:
            pass
        LOG(name).debug(message)

    return echo
Ejemplo n.º 30
0
    def __init__(self, key_phrase="hey OwO", config=None, lang="en-us"):
        super(PreciseHotword, self).__init__(key_phrase, config, lang)
        from precise_runner import (PreciseRunner, PreciseEngine,
                                    ReadWriteStream)
        local_conf = LocalConf(USER_CONFIG)
        if local_conf.get('precise', {}).get('dist_url') == \
                'http://bootstrap.owo.ai/artifacts/static/daily/':
            del local_conf['precise']['dist_url']
            local_conf.store()
            Configuration.updated(None)

        self.download_complete = True

        self.show_download_progress = Timer(0, lambda: None)
        precise_config = Configuration.get()['precise']
        precise_exe = self.install_exe(precise_config['dist_url'])

        local_model = self.config.get('local_model_file')
        if local_model:
            self.precise_model = expanduser(local_model)
        else:
            self.precise_model = self.install_model(
                precise_config['model_url'],
                key_phrase.replace(' ', '-')).replace('.tar.gz', '.pb')

        self.has_found = False
        self.stream = ReadWriteStream()

        def on_activation():
            self.has_found = True

        self.runner = PreciseRunner(PreciseEngine(precise_exe,
                                                  self.precise_model),
                                    stream=self.stream,
                                    on_activation=on_activation)
        self.runner.start()