2018-07-30 22:08:06 +02:00
"""
. . moduleauthor : : Fabio Manganiello < blacklight86 @gmail.com >
. . license : : MIT
"""
2017-12-22 10:18:04 +01:00
import json
import os
2017-12-22 10:43:43 +01:00
import subprocess
2017-12-22 10:18:04 +01:00
import time
import google . oauth2 . credentials
from google . assistant . library import Assistant
from google . assistant . library . event import EventType
from google . assistant . library . file_helpers import existing_file
2017-12-22 10:21:31 +01:00
from platypush . backend import Backend
2017-12-24 01:03:26 +01:00
from platypush . message . event . assistant import \
2018-05-25 18:26:02 +02:00
ConversationStartEvent , ConversationEndEvent , ConversationTimeoutEvent , \
2018-06-20 19:20:23 +02:00
ResponseEvent , NoResponseEvent , SpeechRecognizedEvent
2017-12-22 10:18:04 +01:00
2018-06-06 20:09:18 +02:00
2017-12-22 10:18:04 +01:00
class AssistantGoogleBackend ( Backend ) :
2018-06-26 00:16:39 +02:00
"""
Google Assistant backend .
It listens for voice commands and post conversation events on the bus .
Triggers :
* : class : ` platypush . message . event . assistant . ConversationStartEvent ` when a new conversation starts
* : class : ` platypush . message . event . assistant . SpeechRecognizedEvent ` when a new voice command is recognized
* : class : ` platypush . message . event . assistant . NoResponse ` when a conversation returned no response
* : class : ` platypush . message . event . assistant . ResponseEvent ` when the assistant is speaking a response
* : class : ` platypush . message . event . assistant . ConversationTimeoutEvent ` when a conversation times out
* : class : ` platypush . message . event . assistant . ConversationEndEvent ` when a new conversation ends
Requires :
2018-07-23 02:11:16 +02:00
* * * google - assistant - library * * ( ` ` pip install google - assistant - library ` ` )
* * * google - assistant - sdk [ samples ] * * ( ` ` pip install google - assistant - sdk [ samples ] ` ` )
2018-06-26 00:16:39 +02:00
"""
2017-12-22 10:18:04 +01:00
2018-07-30 22:08:06 +02:00
def __init__ ( self ,
credentials_file = os . path . join (
os . path . expanduser ( ' ~/.config ' ) ,
' google-oauthlib-tool ' , ' credentials.json ' ) ,
device_model_id = ' Platypush ' , * * kwargs ) :
2018-06-26 00:16:39 +02:00
"""
: 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
: param device_model_id : Device model ID to use for the assistant ( default : Platypush )
: type device_model_id : str
2017-12-22 10:43:43 +01:00
"""
2017-12-22 10:18:04 +01:00
super ( ) . __init__ ( * * kwargs )
self . credentials_file = credentials_file
2018-01-09 14:16:06 +01:00
self . device_model_id = device_model_id
2017-12-24 01:03:26 +01:00
self . assistant = None
2017-12-22 10:18:04 +01:00
2017-12-22 10:43:43 +01:00
with open ( self . credentials_file , ' r ' ) as f :
2017-12-22 10:18:04 +01:00
self . credentials = google . oauth2 . credentials . Credentials ( token = None ,
* * json . load ( f ) )
2018-06-06 20:09:18 +02:00
self . logger . info ( ' Initialized Google Assistant backend ' )
2017-12-22 10:18:04 +01:00
def _process_event ( self , event ) :
2018-06-06 20:09:18 +02:00
self . logger . info ( ' Received assistant event: {} ' . format ( event ) )
2017-12-24 01:03:26 +01:00
if event . type == EventType . ON_CONVERSATION_TURN_STARTED :
self . bus . post ( ConversationStartEvent ( ) )
elif event . type == EventType . ON_CONVERSATION_TURN_FINISHED :
2018-06-20 19:20:23 +02:00
if not event . args . get ( ' with_follow_on_turn ' ) :
self . bus . post ( ConversationEndEvent ( ) )
2018-05-25 18:18:16 +02:00
elif event . type == EventType . ON_CONVERSATION_TURN_TIMEOUT :
self . bus . post ( ConversationTimeoutEvent ( ) )
2018-05-25 18:26:02 +02:00
elif event . type == EventType . ON_NO_RESPONSE :
self . bus . post ( NoResponseEvent ( ) )
2018-06-21 01:29:04 +02:00
elif hasattr ( EventType , ' ON_RENDER_RESPONSE ' ) and event . type == EventType . ON_RENDER_RESPONSE :
2018-06-20 19:20:23 +02:00
self . bus . post ( ResponseEvent ( response_text = event . args . get ( ' text ' ) ) )
2017-12-22 10:43:43 +01:00
elif event . type == EventType . ON_RECOGNIZING_SPEECH_FINISHED :
phrase = event . args [ ' text ' ] . lower ( ) . strip ( )
2018-06-06 20:09:18 +02:00
self . logger . info ( ' Speech recognized: {} ' . format ( phrase ) )
2017-12-24 01:03:26 +01:00
self . bus . post ( SpeechRecognizedEvent ( phrase = phrase ) )
2017-12-22 10:18:04 +01:00
2017-12-26 15:06:59 +01:00
def start_conversation ( self ) :
2018-06-26 00:16:39 +02:00
""" Starts an assistant conversation """
2018-07-30 22:08:06 +02:00
if self . assistant :
self . assistant . start_conversation ( )
2017-12-26 15:06:59 +01:00
2017-12-24 02:35:45 +01:00
def stop_conversation ( self ) :
2018-06-26 00:16:39 +02:00
""" Stops an assistant conversation """
2018-07-30 22:08:06 +02:00
if self . assistant :
self . assistant . stop_conversation ( )
2017-12-24 02:35:45 +01:00
2017-12-22 10:18:04 +01:00
def run ( self ) :
super ( ) . run ( )
2018-01-09 14:16:06 +01:00
with Assistant ( self . credentials , self . device_model_id ) as assistant :
2017-12-24 02:35:45 +01:00
self . assistant = assistant
2017-12-24 01:03:26 +01:00
for event in assistant . start ( ) :
2017-12-22 10:18:04 +01:00
self . _process_event ( event )
# vim:sw=4:ts=4:et: