Ran Black on script

This commit is contained in:
Melissa LeBlanc-Williams 2020-10-16 09:42:35 -06:00
parent b6f941aaf2
commit b7b17a70cb

View file

@ -24,7 +24,7 @@ import sys
import time
import uuid
sys.path.append('env/lib/python3.7/site-packages/googlesamples/assistant/grpc')
sys.path.append("env/lib/python3.7/site-packages/googlesamples/assistant/grpc")
import click
import grpc
@ -34,17 +34,12 @@ import google.oauth2.credentials
from google.assistant.embedded.v1alpha2 import (
embedded_assistant_pb2,
embedded_assistant_pb2_grpc
embedded_assistant_pb2_grpc,
)
from tenacity import retry, stop_after_attempt, retry_if_exception
try:
from . import (
assistant_helpers,
audio_helpers,
browser_helpers,
device_helpers
)
from . import assistant_helpers, audio_helpers, browser_helpers, device_helpers
except (SystemError, ImportError):
import assistant_helpers
import audio_helpers
@ -52,32 +47,40 @@ except (SystemError, ImportError):
import device_helpers
try:
import board
from digitalio import DigitalInOut, Direction, Pull
import adafruit_dotstar
import board
from digitalio import DigitalInOut, Direction, Pull
import adafruit_dotstar
except ImportError:
print("Blinka not installed? Run 'pip3 install adafruit-circuitpython-dotstar'")
raise ImportError("Blinka not installed? Run 'pip3 install adafruit-circuitpython-dotstar'")
print("Blinka not installed? Run 'pip3 install adafruit-circuitpython-dotstar'")
raise ImportError(
"Blinka not installed? Run 'pip3 install adafruit-circuitpython-dotstar'"
)
# Setup button
button = DigitalInOut(board.D17)
button.switch_to_input()
# Setup DotStar LEDs
dots = adafruit_dotstar.DotStar(board.D6, board.D5, 3, auto_write=True,
brightness=0.2, pixel_order=adafruit_dotstar.BGR)
dots = adafruit_dotstar.DotStar(
board.D6,
board.D5,
3,
auto_write=True,
brightness=0.2,
pixel_order=adafruit_dotstar.BGR,
)
dots.fill(0x000000)
# Setup OLED
i2c = board.I2C()
ASSISTANT_API_ENDPOINT = 'embeddedassistant.googleapis.com'
ASSISTANT_API_ENDPOINT = "embeddedassistant.googleapis.com"
END_OF_UTTERANCE = embedded_assistant_pb2.AssistResponse.END_OF_UTTERANCE
DIALOG_FOLLOW_ON = embedded_assistant_pb2.DialogStateOut.DIALOG_FOLLOW_ON
CLOSE_MICROPHONE = embedded_assistant_pb2.DialogStateOut.CLOSE_MICROPHONE
PLAYING = embedded_assistant_pb2.ScreenOutConfig.PLAYING
DEFAULT_GRPC_DEADLINE = 60 * 3 + 5
class SampleAssistant(object):
"""Sample Assistant that supports conversations and device actions.
@ -93,9 +96,17 @@ class SampleAssistant(object):
device_handler: callback for device actions.
"""
def __init__(self, language_code, device_model_id, device_id,
conversation_stream, display,
channel, deadline_sec, device_handler):
def __init__(
self,
language_code,
device_model_id,
device_id,
conversation_stream,
display,
channel,
deadline_sec,
device_handler,
):
self.language_code = language_code
self.device_model_id = device_model_id
self.device_id = device_id
@ -113,9 +124,7 @@ class SampleAssistant(object):
self.is_new_conversation = True
# Create Google Assistant API gRPC client.
self.assistant = embedded_assistant_pb2_grpc.EmbeddedAssistantStub(
channel
)
self.assistant = embedded_assistant_pb2_grpc.EmbeddedAssistantStub(channel)
self.deadline = deadline_sec
self.device_handler = device_handler
@ -131,12 +140,15 @@ class SampleAssistant(object):
def is_grpc_error_unavailable(e):
is_grpc_error = isinstance(e, grpc.RpcError)
if is_grpc_error and (e.code() == grpc.StatusCode.UNAVAILABLE):
logging.error('grpc unavailable error: %s', e)
logging.error("grpc unavailable error: %s", e)
return True
return False
@retry(reraise=True, stop=stop_after_attempt(3),
retry=retry_if_exception(is_grpc_error_unavailable))
@retry(
reraise=True,
stop=stop_after_attempt(3),
retry=retry_if_exception(is_grpc_error_unavailable),
)
def assist(self):
"""Send a voice request to the Assistant and playback the response.
@ -146,50 +158,48 @@ class SampleAssistant(object):
device_actions_futures = []
self.conversation_stream.start_recording()
logging.info('Recording audio request.')
logging.info("Recording audio request.")
def iter_log_assist_requests():
for c in self.gen_assist_requests():
assistant_helpers.log_assist_request_without_audio(c)
yield c
logging.debug('Reached end of AssistRequest iteration.')
logging.debug("Reached end of AssistRequest iteration.")
# This generator yields AssistResponse proto messages
# received from the gRPC Google Assistant API.
for resp in self.assistant.Assist(iter_log_assist_requests(),
self.deadline):
for resp in self.assistant.Assist(iter_log_assist_requests(), self.deadline):
assistant_helpers.log_assist_response_without_audio(resp)
if resp.event_type == END_OF_UTTERANCE:
logging.info('End of audio request detected.')
logging.info('Stopping recording.')
logging.info("End of audio request detected.")
logging.info("Stopping recording.")
self.conversation_stream.stop_recording()
if resp.speech_results:
logging.info('Transcript of user request: "%s".',
' '.join(r.transcript
for r in resp.speech_results))
logging.info(
'Transcript of user request: "%s".',
" ".join(r.transcript for r in resp.speech_results),
)
if len(resp.audio_out.audio_data) > 0:
if not self.conversation_stream.playing:
self.conversation_stream.stop_recording()
self.conversation_stream.start_playback()
logging.info('Playing assistant response.')
logging.info("Playing assistant response.")
self.conversation_stream.write(resp.audio_out.audio_data)
if resp.dialog_state_out.conversation_state:
conversation_state = resp.dialog_state_out.conversation_state
logging.debug('Updating conversation state.')
logging.debug("Updating conversation state.")
self.conversation_state = conversation_state
if resp.dialog_state_out.volume_percentage != 0:
volume_percentage = resp.dialog_state_out.volume_percentage
logging.info('Setting volume to %s%%', volume_percentage)
logging.info("Setting volume to %s%%", volume_percentage)
self.conversation_stream.volume_percentage = volume_percentage
if resp.dialog_state_out.microphone_mode == DIALOG_FOLLOW_ON:
continue_conversation = True
logging.info('Expecting follow-on query from user.')
logging.info("Expecting follow-on query from user.")
elif resp.dialog_state_out.microphone_mode == CLOSE_MICROPHONE:
continue_conversation = False
if resp.device_action.device_request_json:
device_request = json.loads(
resp.device_action.device_request_json
)
device_request = json.loads(resp.device_action.device_request_json)
fs = self.device_handler(device_request)
if fs:
device_actions_futures.extend(fs)
@ -198,10 +208,10 @@ class SampleAssistant(object):
system_browser.display(resp.screen_out.data)
if len(device_actions_futures):
logging.info('Waiting for device executions to complete.')
logging.info("Waiting for device executions to complete.")
concurrent.futures.wait(device_actions_futures)
logging.info('Finished playing assistant response.')
logging.info("Finished playing assistant response.")
self.conversation_stream.stop_playback()
return continue_conversation
@ -210,11 +220,11 @@ class SampleAssistant(object):
config = embedded_assistant_pb2.AssistConfig(
audio_in_config=embedded_assistant_pb2.AudioInConfig(
encoding='LINEAR16',
encoding="LINEAR16",
sample_rate_hertz=self.conversation_stream.sample_rate,
),
audio_out_config=embedded_assistant_pb2.AudioOutConfig(
encoding='LINEAR16',
encoding="LINEAR16",
sample_rate_hertz=self.conversation_stream.sample_rate,
volume_percentage=self.conversation_stream.volume_percentage,
),
@ -226,7 +236,7 @@ class SampleAssistant(object):
device_config=embedded_assistant_pb2.DeviceConfig(
device_id=self.device_id,
device_model_id=self.device_model_id,
)
),
)
if self.display:
config.screen_out_config.screen_mode = PLAYING
@ -241,84 +251,155 @@ class SampleAssistant(object):
@click.command()
@click.option('--api-endpoint', default=ASSISTANT_API_ENDPOINT,
metavar='<api endpoint>', show_default=True,
help='Address of Google Assistant API service.')
@click.option('--credentials',
metavar='<credentials>', show_default=True,
default=os.path.join(click.get_app_dir('google-oauthlib-tool'),
'credentials.json'),
help='Path to read OAuth2 credentials.')
@click.option('--project-id',
metavar='<project id>',
help=('Google Developer Project ID used for registration '
'if --device-id is not specified'))
@click.option('--device-model-id',
metavar='<device model id>',
help=(('Unique device model identifier, '
'if not specifed, it is read from --device-config')))
@click.option('--device-id',
metavar='<device id>',
help=(('Unique registered device instance identifier, '
'if not specified, it is read from --device-config, '
'if no device_config found: a new device is registered '
'using a unique id and a new device config is saved')))
@click.option('--device-config', show_default=True,
metavar='<device config>',
default=os.path.join(
click.get_app_dir('googlesamples-assistant'),
'device_config.json'),
help='Path to save and restore the device configuration')
@click.option('--lang', show_default=True,
metavar='<language code>',
default='en-US',
help='Language code of the Assistant')
@click.option('--display', is_flag=True, default=False,
help='Enable visual display of Assistant responses in HTML.')
@click.option('--verbose', '-v', is_flag=True, default=False,
help='Verbose logging.')
@click.option('--input-audio-file', '-i',
metavar='<input file>',
help='Path to input audio file. '
'If missing, uses audio capture')
@click.option('--output-audio-file', '-o',
metavar='<output file>',
help='Path to output audio file. '
'If missing, uses audio playback')
@click.option('--audio-sample-rate',
default=audio_helpers.DEFAULT_AUDIO_SAMPLE_RATE,
metavar='<audio sample rate>', show_default=True,
help='Audio sample rate in hertz.')
@click.option('--audio-sample-width',
default=audio_helpers.DEFAULT_AUDIO_SAMPLE_WIDTH,
metavar='<audio sample width>', show_default=True,
help='Audio sample width in bytes.')
@click.option('--audio-iter-size',
default=audio_helpers.DEFAULT_AUDIO_ITER_SIZE,
metavar='<audio iter size>', show_default=True,
help='Size of each read during audio stream iteration in bytes.')
@click.option('--audio-block-size',
default=audio_helpers.DEFAULT_AUDIO_DEVICE_BLOCK_SIZE,
metavar='<audio block size>', show_default=True,
help=('Block size in bytes for each audio device '
'read and write operation.'))
@click.option('--audio-flush-size',
default=audio_helpers.DEFAULT_AUDIO_DEVICE_FLUSH_SIZE,
metavar='<audio flush size>', show_default=True,
help=('Size of silence data in bytes written '
'during flush operation'))
@click.option('--grpc-deadline', default=DEFAULT_GRPC_DEADLINE,
metavar='<grpc deadline>', show_default=True,
help='gRPC deadline in seconds')
@click.option('--once', default=False, is_flag=True,
help='Force termination after a single conversation.')
def main(api_endpoint, credentials, project_id,
device_model_id, device_id, device_config,
lang, display, verbose,
input_audio_file, output_audio_file,
audio_sample_rate, audio_sample_width,
audio_iter_size, audio_block_size, audio_flush_size,
grpc_deadline, once, *args, **kwargs):
@click.option(
"--api-endpoint",
default=ASSISTANT_API_ENDPOINT,
metavar="<api endpoint>",
show_default=True,
help="Address of Google Assistant API service.",
)
@click.option(
"--credentials",
metavar="<credentials>",
show_default=True,
default=os.path.join(click.get_app_dir("google-oauthlib-tool"), "credentials.json"),
help="Path to read OAuth2 credentials.",
)
@click.option(
"--project-id",
metavar="<project id>",
help=(
"Google Developer Project ID used for registration "
"if --device-id is not specified"
),
)
@click.option(
"--device-model-id",
metavar="<device model id>",
help=(
(
"Unique device model identifier, "
"if not specifed, it is read from --device-config"
)
),
)
@click.option(
"--device-id",
metavar="<device id>",
help=(
(
"Unique registered device instance identifier, "
"if not specified, it is read from --device-config, "
"if no device_config found: a new device is registered "
"using a unique id and a new device config is saved"
)
),
)
@click.option(
"--device-config",
show_default=True,
metavar="<device config>",
default=os.path.join(
click.get_app_dir("googlesamples-assistant"), "device_config.json"
),
help="Path to save and restore the device configuration",
)
@click.option(
"--lang",
show_default=True,
metavar="<language code>",
default="en-US",
help="Language code of the Assistant",
)
@click.option(
"--display",
is_flag=True,
default=False,
help="Enable visual display of Assistant responses in HTML.",
)
@click.option("--verbose", "-v", is_flag=True, default=False, help="Verbose logging.")
@click.option(
"--input-audio-file",
"-i",
metavar="<input file>",
help="Path to input audio file. " "If missing, uses audio capture",
)
@click.option(
"--output-audio-file",
"-o",
metavar="<output file>",
help="Path to output audio file. " "If missing, uses audio playback",
)
@click.option(
"--audio-sample-rate",
default=audio_helpers.DEFAULT_AUDIO_SAMPLE_RATE,
metavar="<audio sample rate>",
show_default=True,
help="Audio sample rate in hertz.",
)
@click.option(
"--audio-sample-width",
default=audio_helpers.DEFAULT_AUDIO_SAMPLE_WIDTH,
metavar="<audio sample width>",
show_default=True,
help="Audio sample width in bytes.",
)
@click.option(
"--audio-iter-size",
default=audio_helpers.DEFAULT_AUDIO_ITER_SIZE,
metavar="<audio iter size>",
show_default=True,
help="Size of each read during audio stream iteration in bytes.",
)
@click.option(
"--audio-block-size",
default=audio_helpers.DEFAULT_AUDIO_DEVICE_BLOCK_SIZE,
metavar="<audio block size>",
show_default=True,
help=("Block size in bytes for each audio device " "read and write operation."),
)
@click.option(
"--audio-flush-size",
default=audio_helpers.DEFAULT_AUDIO_DEVICE_FLUSH_SIZE,
metavar="<audio flush size>",
show_default=True,
help=("Size of silence data in bytes written " "during flush operation"),
)
@click.option(
"--grpc-deadline",
default=DEFAULT_GRPC_DEADLINE,
metavar="<grpc deadline>",
show_default=True,
help="gRPC deadline in seconds",
)
@click.option(
"--once",
default=False,
is_flag=True,
help="Force termination after a single conversation.",
)
def main(
api_endpoint,
credentials,
project_id,
device_model_id,
device_id,
device_config,
lang,
display,
verbose,
input_audio_file,
output_audio_file,
audio_sample_rate,
audio_sample_width,
audio_iter_size,
audio_block_size,
audio_flush_size,
grpc_deadline,
once,
*args,
**kwargs
):
"""Samples for the Google Assistant API.
Examples:
@ -339,53 +420,52 @@ def main(api_endpoint, credentials, project_id,
# Load OAuth 2.0 credentials.
try:
with open(credentials, 'r') as f:
credentials = google.oauth2.credentials.Credentials(token=None,
**json.load(f))
with open(credentials, "r") as f:
credentials = google.oauth2.credentials.Credentials(
token=None, **json.load(f)
)
http_request = google.auth.transport.requests.Request()
credentials.refresh(http_request)
except Exception as e:
logging.error('Error loading credentials: %s', e)
logging.error('Run google-oauthlib-tool to initialize '
'new OAuth 2.0 credentials.')
logging.error("Error loading credentials: %s", e)
logging.error(
"Run google-oauthlib-tool to initialize " "new OAuth 2.0 credentials."
)
sys.exit(-1)
# Create an authorized gRPC channel.
grpc_channel = google.auth.transport.grpc.secure_authorized_channel(
credentials, http_request, api_endpoint)
logging.info('Connecting to %s', api_endpoint)
credentials, http_request, api_endpoint
)
logging.info("Connecting to %s", api_endpoint)
# Configure audio source and sink.
audio_device = None
if input_audio_file:
audio_source = audio_helpers.WaveSource(
open(input_audio_file, 'rb'),
open(input_audio_file, "rb"),
sample_rate=audio_sample_rate,
sample_width=audio_sample_width
sample_width=audio_sample_width,
)
else:
audio_source = audio_device = (
audio_device or audio_helpers.SoundDeviceStream(
sample_rate=audio_sample_rate,
sample_width=audio_sample_width,
block_size=audio_block_size,
flush_size=audio_flush_size
)
audio_source = audio_device = audio_device or audio_helpers.SoundDeviceStream(
sample_rate=audio_sample_rate,
sample_width=audio_sample_width,
block_size=audio_block_size,
flush_size=audio_flush_size,
)
if output_audio_file:
audio_sink = audio_helpers.WaveSink(
open(output_audio_file, 'wb'),
open(output_audio_file, "wb"),
sample_rate=audio_sample_rate,
sample_width=audio_sample_width
sample_width=audio_sample_width,
)
else:
audio_sink = audio_device = (
audio_device or audio_helpers.SoundDeviceStream(
sample_rate=audio_sample_rate,
sample_width=audio_sample_width,
block_size=audio_block_size,
flush_size=audio_flush_size
)
audio_sink = audio_device = audio_device or audio_helpers.SoundDeviceStream(
sample_rate=audio_sample_rate,
sample_width=audio_sample_width,
block_size=audio_block_size,
flush_size=audio_flush_size,
)
# Create conversation stream with the given audio source and sink.
conversation_stream = audio_helpers.ConversationStream(
@ -399,69 +479,77 @@ def main(api_endpoint, credentials, project_id,
try:
with open(device_config) as f:
device = json.load(f)
device_id = device['id']
device_model_id = device['model_id']
logging.info("Using device model %s and device id %s",
device_model_id,
device_id)
device_id = device["id"]
device_model_id = device["model_id"]
logging.info(
"Using device model %s and device id %s", device_model_id, device_id
)
except Exception as e:
logging.warning('Device config not found: %s' % e)
logging.info('Registering device')
logging.warning("Device config not found: %s" % e)
logging.info("Registering device")
if not device_model_id:
logging.error('Option --device-model-id required '
'when registering a device instance.')
logging.error(
"Option --device-model-id required "
"when registering a device instance."
)
sys.exit(-1)
if not project_id:
logging.error('Option --project-id required '
'when registering a device instance.')
logging.error(
"Option --project-id required "
"when registering a device instance."
)
sys.exit(-1)
device_base_url = (
'https://%s/v1alpha2/projects/%s/devices' % (api_endpoint,
project_id)
device_base_url = "https://%s/v1alpha2/projects/%s/devices" % (
api_endpoint,
project_id,
)
device_id = str(uuid.uuid1())
payload = {
'id': device_id,
'model_id': device_model_id,
'client_type': 'SDK_SERVICE'
"id": device_id,
"model_id": device_model_id,
"client_type": "SDK_SERVICE",
}
session = google.auth.transport.requests.AuthorizedSession(
credentials
)
session = google.auth.transport.requests.AuthorizedSession(credentials)
r = session.post(device_base_url, data=json.dumps(payload))
if r.status_code != 200:
logging.error('Failed to register device: %s', r.text)
logging.error("Failed to register device: %s", r.text)
sys.exit(-1)
logging.info('Device registered: %s', device_id)
logging.info("Device registered: %s", device_id)
pathlib.Path(os.path.dirname(device_config)).mkdir(exist_ok=True)
with open(device_config, 'w') as f:
with open(device_config, "w") as f:
json.dump(payload, f)
device_handler = device_helpers.DeviceRequestHandler(device_id)
@device_handler.command('action.devices.commands.OnOff')
@device_handler.command("action.devices.commands.OnOff")
def onoff(on):
if on:
logging.info('Turning device on')
logging.info("Turning device on")
else:
logging.info('Turning device off')
logging.info("Turning device off")
@device_handler.command('com.example.commands.BlinkLight')
@device_handler.command("com.example.commands.BlinkLight")
def blink(speed, number):
logging.info('Blinking device %s times.' % number)
logging.info("Blinking device %s times." % number)
delay = 1
if speed == "SLOWLY":
delay = 2
elif speed == "QUICKLY":
delay = 0.5
for i in range(int(number)):
logging.info('Device is blinking.')
logging.info("Device is blinking.")
time.sleep(delay)
with SampleAssistant(lang, device_model_id, device_id,
conversation_stream, display,
grpc_channel, grpc_deadline,
device_handler) as assistant:
with SampleAssistant(
lang,
device_model_id,
device_id,
conversation_stream,
display,
grpc_channel,
grpc_deadline,
device_handler,
) as assistant:
# If file arguments are supplied:
# exit after the first turn of the conversation.
if input_audio_file or output_audio_file:
@ -497,5 +585,5 @@ def main(api_endpoint, credentials, project_id,
break
if __name__ == '__main__':
if __name__ == "__main__":
main()