forked from platypush/platypush
Fixed some pylint warnings
This commit is contained in:
parent
a0ac30e9b6
commit
81803a364d
6 changed files with 113 additions and 70 deletions
|
@ -1,6 +1,6 @@
|
|||
MIT License
|
||||
|
||||
Copyright (c) 2017, Fabio Manganiello
|
||||
Copyright (c) 2017, 2018 Fabio Manganiello
|
||||
|
||||
Permission is hereby granted, free of charge, to any person obtaining a copy
|
||||
of this software and associated documentation files (the "Software"), to deal
|
||||
|
|
|
@ -1,3 +1,10 @@
|
|||
"""
|
||||
Platypush
|
||||
|
||||
.. moduleauthor:: Fabio Manganiello <blacklight86@gmail.com>
|
||||
.. license:: MIT
|
||||
"""
|
||||
|
||||
import argparse
|
||||
import logging
|
||||
import sys
|
||||
|
@ -18,30 +25,29 @@ from .message.response import Response
|
|||
__author__ = 'Fabio Manganiello <blacklight86@gmail.com>'
|
||||
__version__ = '0.9'
|
||||
|
||||
#-----------#
|
||||
LOGGER = logging.getLogger(__name__)
|
||||
|
||||
logger = logging.getLogger(__name__)
|
||||
|
||||
class Daemon(object):
|
||||
class Daemon:
|
||||
""" Main class for the Platypush daemon """
|
||||
|
||||
""" Configuration file (default: either ~/.config/platypush/config.yaml or
|
||||
/etc/platypush/config.yaml) """
|
||||
# Configuration file (default: either ~/.config/platypush/config.yaml or
|
||||
# /etc/platypush/config.yaml
|
||||
config_file = None
|
||||
|
||||
""" Application bus. It's an internal queue where:
|
||||
- backends will post the messages they receive
|
||||
- plugins will post the responses they process """
|
||||
# Application bus. It's an internal queue where:
|
||||
# - backends will post the messages they receive
|
||||
# - plugins will post the responses they process
|
||||
bus = None
|
||||
|
||||
""" backend_name => backend_obj map """
|
||||
# backend_name => backend_obj map
|
||||
backends = None
|
||||
|
||||
""" number of executions retries before a request fails """
|
||||
# number of executions retries before a request fails
|
||||
n_tries = 2
|
||||
|
||||
def __init__(self, config_file=None, requests_to_process=None):
|
||||
""" Constructor
|
||||
"""
|
||||
Constructor
|
||||
Params:
|
||||
config_file -- Configuration file override (default: None)
|
||||
requests_to_process -- Exit after processing the specified number
|
||||
|
@ -58,7 +64,8 @@ class Daemon(object):
|
|||
|
||||
@classmethod
|
||||
def build_from_cmdline(cls, args):
|
||||
""" Build the app from command line arguments.
|
||||
"""
|
||||
Build the app from command line arguments.
|
||||
Params:
|
||||
args -- Your sys.argv[1:] [List of strings]
|
||||
"""
|
||||
|
@ -70,30 +77,34 @@ class Daemon(object):
|
|||
return cls(config_file=opts.config)
|
||||
|
||||
def on_message(self):
|
||||
""" Default message handler """
|
||||
"""
|
||||
Default message handler
|
||||
"""
|
||||
|
||||
def _f(msg):
|
||||
""" on_message closure
|
||||
"""
|
||||
on_message closure
|
||||
Params:
|
||||
msg -- platypush.message.Message instance """
|
||||
msg -- platypush.message.Message instance
|
||||
"""
|
||||
|
||||
if isinstance(msg, Request):
|
||||
try:
|
||||
msg.execute(n_tries=self.n_tries)
|
||||
except PermissionError:
|
||||
logger.info('Dropped unauthorized request: {}'.format(msg))
|
||||
LOGGER.info('Dropped unauthorized request: {}'.format(msg))
|
||||
|
||||
self.processed_requests += 1
|
||||
if self.requests_to_process \
|
||||
and self.processed_requests >= self.requests_to_process:
|
||||
self.stop_app()
|
||||
elif isinstance(msg, Response):
|
||||
logger.info('Received response: {}'.format(msg))
|
||||
LOGGER.info('Received response: {}'.format(msg))
|
||||
elif isinstance(msg, StopEvent) and msg.targets_me():
|
||||
logger.info('Received STOP event: {}'.format(msg))
|
||||
LOGGER.info('Received STOP event: {}'.format(msg))
|
||||
self.stop_app()
|
||||
elif isinstance(msg, Event):
|
||||
logger.info('Received event: {}'.format(msg))
|
||||
LOGGER.info('Received event: {}'.format(msg))
|
||||
self.event_processor.process_event(msg)
|
||||
|
||||
return _f
|
||||
|
@ -124,17 +135,20 @@ class Daemon(object):
|
|||
# Poll for messages on the bus
|
||||
try:
|
||||
self.bus.poll()
|
||||
except KeyboardInterrupt as e:
|
||||
logger.info('SIGINT received, terminating application')
|
||||
except KeyboardInterrupt:
|
||||
LOGGER.info('SIGINT received, terminating application')
|
||||
finally:
|
||||
self.stop_app()
|
||||
|
||||
|
||||
def main():
|
||||
"""
|
||||
Platypush daemon main
|
||||
"""
|
||||
|
||||
print('Starting platypush v.{}'.format(__version__))
|
||||
app = Daemon.build_from_cmdline(sys.argv[1:])
|
||||
app.start()
|
||||
|
||||
|
||||
# vim:sw=4:ts=4:et:
|
||||
|
||||
|
|
|
@ -1,3 +1,8 @@
|
|||
"""
|
||||
.. moduleauthor:: Fabio Manganiello <blacklight86@gmail.com>
|
||||
.. license:: MIT
|
||||
"""
|
||||
|
||||
import importlib
|
||||
import logging
|
||||
import sys
|
||||
|
|
|
@ -1,3 +1,8 @@
|
|||
"""
|
||||
.. moduleauthor:: Fabio Manganiello <blacklight86@gmail.com>
|
||||
.. license:: MIT
|
||||
"""
|
||||
|
||||
import json
|
||||
import os
|
||||
import subprocess
|
||||
|
@ -36,10 +41,11 @@ class AssistantGoogleBackend(Backend):
|
|||
* **google-assistant-sdk[samples]** (``pip install google-assistant-sdk[samples]``)
|
||||
"""
|
||||
|
||||
def __init__(self, credentials_file=os.path.join(
|
||||
os.path.expanduser('~/.config'),
|
||||
'google-oauthlib-tool', 'credentials.json'),
|
||||
device_model_id='Platypush', **kwargs):
|
||||
def __init__(self,
|
||||
credentials_file=os.path.join(
|
||||
os.path.expanduser('~/.config'),
|
||||
'google-oauthlib-tool', 'credentials.json'),
|
||||
device_model_id='Platypush', **kwargs):
|
||||
"""
|
||||
:param credentials_file: Path to the Google OAuth credentials file (default: ~/.config/google-oauthlib-tool/credentials.json). See https://developers.google.com/assistant/sdk/guides/library/python/embed/install-sample#generate_credentials for how to get your own credentials file.
|
||||
:type credentials_file: str
|
||||
|
@ -80,12 +86,14 @@ class AssistantGoogleBackend(Backend):
|
|||
|
||||
def start_conversation(self):
|
||||
""" Starts an assistant conversation """
|
||||
if self.assistant: self.assistant.start_conversation()
|
||||
if self.assistant:
|
||||
self.assistant.start_conversation()
|
||||
|
||||
|
||||
def stop_conversation(self):
|
||||
""" Stops an assistant conversation """
|
||||
if self.assistant: self.assistant.stop_conversation()
|
||||
if self.assistant:
|
||||
self.assistant.stop_conversation()
|
||||
|
||||
|
||||
def run(self):
|
||||
|
@ -98,4 +106,3 @@ class AssistantGoogleBackend(Backend):
|
|||
|
||||
|
||||
# vim:sw=4:ts=4:et:
|
||||
|
||||
|
|
|
@ -1,22 +1,24 @@
|
|||
"""
|
||||
.. moduleauthor:: Fabio Manganiello <blacklight86@gmail.com>
|
||||
.. license:: MIT
|
||||
"""
|
||||
|
||||
import concurrent
|
||||
import json
|
||||
import logging
|
||||
import os
|
||||
import threading
|
||||
import time
|
||||
|
||||
import grpc
|
||||
import google.auth.transport.grpc
|
||||
import google.auth.transport.requests
|
||||
import google.oauth2.credentials
|
||||
from google.assistant.embedded.v1alpha2 import embedded_assistant_pb2, embedded_assistant_pb2_grpc
|
||||
|
||||
import googlesamples.assistant.grpc.audio_helpers as audio_helpers
|
||||
import googlesamples.assistant.grpc.device_helpers as device_helpers
|
||||
import googlesamples.assistant.grpc.assistant_helpers as assistant_helpers
|
||||
|
||||
from tenacity import retry, stop_after_attempt, retry_if_exception
|
||||
from google.assistant.embedded.v1alpha2 import (
|
||||
embedded_assistant_pb2,
|
||||
embedded_assistant_pb2_grpc
|
||||
)
|
||||
|
||||
|
||||
from platypush.backend import Backend
|
||||
|
@ -53,15 +55,16 @@ class AssistantGooglePushtotalkBackend(Backend):
|
|||
audio_flush_size = audio_helpers.DEFAULT_AUDIO_DEVICE_FLUSH_SIZE
|
||||
grpc_deadline = 60 * 3 + 5
|
||||
|
||||
def __init__(self, credentials_file=os.path.join(
|
||||
os.path.expanduser('~'), '.config',
|
||||
'google-oauthlib-tool', 'credentials.json'),
|
||||
device_config=os.path.join(
|
||||
os.path.expanduser('~'), '.config', 'googlesamples-assistant',
|
||||
'device_config.json'),
|
||||
lang='en-US',
|
||||
conversation_start_fifo = os.path.join(os.path.sep, 'tmp', 'pushtotalk.fifo'),
|
||||
*args, **kwargs):
|
||||
def __init__(self, *args,
|
||||
credentials_file=os.path.join(
|
||||
os.path.expanduser('~'), '.config',
|
||||
'google-oauthlib-tool', 'credentials.json'),
|
||||
device_config=os.path.join(
|
||||
os.path.expanduser('~'), '.config', 'googlesamples-assistant',
|
||||
'device_config.json'),
|
||||
lang='en-US',
|
||||
conversation_start_fifo=os.path.join(os.path.sep, 'tmp', 'pushtotalk.fifo'),
|
||||
**kwargs):
|
||||
"""
|
||||
:param credentials_file: Path to the Google OAuth credentials file (default: ~/.config/google-oauthlib-tool/credentials.json). See https://developers.google.com/assistant/sdk/guides/library/python/embed/install-sample#generate_credentials for how to get your own credentials file.
|
||||
:type credentials_file: str
|
||||
|
@ -98,10 +101,10 @@ class AssistantGooglePushtotalkBackend(Backend):
|
|||
**json.load(f))
|
||||
http_request = google.auth.transport.requests.Request()
|
||||
credentials.refresh(http_request)
|
||||
except:
|
||||
self.logger.error('Error loading credentials: %s', e)
|
||||
except Exception as ex:
|
||||
self.logger.error('Error loading credentials: %s', str(ex))
|
||||
self.logger.error('Run google-oauthlib-tool to initialize '
|
||||
'new OAuth 2.0 credentials.')
|
||||
'new OAuth 2.0 credentials.')
|
||||
raise
|
||||
|
||||
# Create an authorized gRPC channel.
|
||||
|
@ -151,43 +154,44 @@ class AssistantGooglePushtotalkBackend(Backend):
|
|||
self.conversation_stream.stop_playback()
|
||||
self.bus.post(ConversationEndEvent())
|
||||
|
||||
def send_message(self, msg):
|
||||
pass
|
||||
|
||||
def on_conversation_start(self):
|
||||
""" Conversation start handler """
|
||||
self.bus.post(ConversationStartEvent())
|
||||
|
||||
def on_conversation_end(self):
|
||||
""" Conversation end handler """
|
||||
self.bus.post(ConversationEndEvent())
|
||||
|
||||
def on_speech_recognized(self, speech):
|
||||
""" Speech recognized handler """
|
||||
self.bus.post(SpeechRecognizedEvent(phrase=speech))
|
||||
|
||||
def run(self):
|
||||
""" Backend executor """
|
||||
super().run()
|
||||
|
||||
with SampleAssistant(self.lang, self.device_model_id, self.device_id,
|
||||
self.conversation_stream,
|
||||
self.grpc_channel, self.grpc_deadline,
|
||||
self.device_handler,
|
||||
on_conversation_start=self.on_conversation_start,
|
||||
on_conversation_end=self.on_conversation_end,
|
||||
on_speech_recognized=self.on_speech_recognized) as self.assistant:
|
||||
self.conversation_stream,
|
||||
self.grpc_channel, self.grpc_deadline,
|
||||
self.device_handler,
|
||||
on_conversation_start=self.on_conversation_start,
|
||||
on_conversation_end=self.on_conversation_end,
|
||||
on_speech_recognized=self.on_speech_recognized) as self.assistant:
|
||||
while not self.should_stop():
|
||||
with open(self.conversation_start_fifo, 'r') as f:
|
||||
for line in f: pass
|
||||
f.read()
|
||||
|
||||
self.logger.info('Received conversation start event')
|
||||
continue_conversation = True
|
||||
user_request = None
|
||||
|
||||
while continue_conversation:
|
||||
(user_request, continue_conversation) = self.assistant.assist()
|
||||
self.logger('User request: {}'.format(user_request))
|
||||
|
||||
self.on_conversation_end()
|
||||
|
||||
|
||||
class SampleAssistant(object):
|
||||
class SampleAssistant:
|
||||
"""Sample Assistant that supports conversations and device actions.
|
||||
|
||||
Args:
|
||||
|
@ -242,11 +246,14 @@ class SampleAssistant(object):
|
|||
if e:
|
||||
return False
|
||||
self.conversation_stream.close()
|
||||
return True
|
||||
|
||||
@staticmethod
|
||||
def is_grpc_error_unavailable(e):
|
||||
""" Returns True if the gRPC is not available """
|
||||
is_grpc_error = isinstance(e, grpc.RpcError)
|
||||
if is_grpc_error and (e.code() == grpc.StatusCode.UNAVAILABLE):
|
||||
self.logger.error('grpc unavailable error: %s', e)
|
||||
print('grpc unavailable error: {}'.format(e))
|
||||
return True
|
||||
return False
|
||||
|
||||
|
@ -288,7 +295,7 @@ class SampleAssistant(object):
|
|||
|
||||
self.logger.info('Transcript of user request: "%s".', user_request)
|
||||
self.logger.info('Playing assistant response.')
|
||||
if len(resp.audio_out.audio_data) > 0:
|
||||
if resp.audio_out.audio_data:
|
||||
self.conversation_stream.write(resp.audio_out.audio_data)
|
||||
if resp.dialog_state_out.conversation_state:
|
||||
conversation_state = resp.dialog_state_out.conversation_state
|
||||
|
@ -311,7 +318,7 @@ class SampleAssistant(object):
|
|||
if fs:
|
||||
device_actions_futures.extend(fs)
|
||||
|
||||
if len(device_actions_futures):
|
||||
if device_actions_futures:
|
||||
self.logger.info('Waiting for device executions to complete.')
|
||||
concurrent.futures.wait(device_actions_futures)
|
||||
|
||||
|
@ -319,7 +326,7 @@ class SampleAssistant(object):
|
|||
|
||||
try:
|
||||
self.conversation_stream.stop_playback()
|
||||
except:
|
||||
except Exception:
|
||||
pass
|
||||
|
||||
if user_request and self.on_speech_recognized:
|
||||
|
@ -331,12 +338,14 @@ class SampleAssistant(object):
|
|||
"""Yields: AssistRequest messages to send to the API."""
|
||||
|
||||
dialog_state_in = embedded_assistant_pb2.DialogStateIn(
|
||||
language_code=self.language_code,
|
||||
conversation_state=b''
|
||||
)
|
||||
language_code=self.language_code,
|
||||
conversation_state=b''
|
||||
)
|
||||
|
||||
if self.conversation_state:
|
||||
self.logger.debug('Sending conversation state.')
|
||||
dialog_state_in.conversation_state = self.conversation_state
|
||||
|
||||
config = embedded_assistant_pb2.AssistConfig(
|
||||
audio_in_config=embedded_assistant_pb2.AudioInConfig(
|
||||
encoding='LINEAR16',
|
||||
|
@ -353,6 +362,7 @@ class SampleAssistant(object):
|
|||
device_model_id=self.device_model_id,
|
||||
)
|
||||
)
|
||||
|
||||
# The first AssistRequest must contain the AssistConfig
|
||||
# and no audio data.
|
||||
yield embedded_assistant_pb2.AssistRequest(config=config)
|
||||
|
@ -362,4 +372,3 @@ class SampleAssistant(object):
|
|||
|
||||
|
||||
# vim:sw=4:ts=4:et:
|
||||
|
||||
|
|
|
@ -1,3 +1,8 @@
|
|||
"""
|
||||
.. moduleauthor:: Fabio Manganiello <blacklight86@gmail.com>
|
||||
.. license:: MIT
|
||||
"""
|
||||
|
||||
import json
|
||||
import os
|
||||
import subprocess
|
||||
|
@ -57,6 +62,10 @@ class AssistantSnowboyBackend(Backend):
|
|||
self.logger.info('Initialized Snowboy hotword detection')
|
||||
|
||||
def hotword_detected(self):
|
||||
"""
|
||||
Callback called on hotword detection
|
||||
"""
|
||||
|
||||
def callback():
|
||||
self.bus.post(HotwordDetectedEvent(hotword=self.hotword))
|
||||
return callback
|
||||
|
@ -67,4 +76,3 @@ class AssistantSnowboyBackend(Backend):
|
|||
|
||||
|
||||
# vim:sw=4:ts=4:et:
|
||||
|
||||
|
|
Loading…
Reference in a new issue