Stiamo transitando da un mondo “mobile first”
ad un mondo “AI first”
Sundai Pichar
La voce sta giocando un ruolo importante in questa fase di transizione da un paradigma “mobile first” ad uno “AI First” sotto forma di assistenti vocali come Google Assistant , Amazon Alexa, Apple Siri. Portando così il potere della voce nel mercato consumer tramite prodotti intelligenti come smart-phones, smart-speakers, smart-watches, ecc. che nascono dalla forte combinazione di hardware, software e intelligenza artificiale (AI).
Per rendere “smart” anche i nostri progetti aggiungendo l’assistente di Google abbiamo due metodi:
[1] L’utillizo della libreria in python Google Assistant Library che è l’ideale per il rapid prototyping per costruire device come AIY Voice Kit.
[2] O il servizio gRPC con Google Assistant Service, che fornisce il binding per diversi linguaggi come Go, Java, C#, Node.js o Ruby.
Queste 2 API sono molto simili in termini di funzionalità, ma la libreria Python fornisce l’attivazione tramite hotword (“Ok Google”) avendo così le mani libere. Invece impiegando l’API gRPC, dobbiamo premere un pulsante (fisico o digitale).
La prima API supporta solo architetture x86-64 e ARMv7 (Raspberry Pi 2 e 3) e non ARMv6 (Raspberry Pi 1), invece con la seconda possiamo usare Google Assistant anche sulla Pi-Zero come avevamo già visto in questo tutorial.
gRPC service
Una conversazione può essere composta da più connessioni gRPC, ciascuna costituita da più richieste e risposte. Ad esempio, se l’utente dice: “aggiungi alla mia lista della spesa” l’assistente risponderà: “Cosa vuoi aggiungere ?”.
Una possibile sequenza di richieste e risposte potrebbe essere:
1 2 3 4 5 6 7 8 9 10 11 |
AssistRequest.config AssistRequest.audio_in AssistRequest.audio_in AssistRequest.audio_in AssistRequest.audio_in AssistResponse.event_type.END_OF_UTTERANCE AssistResponse.speech_results.transcript “aggiungi alla mia lista della spesa” AssistResponse.dialog_state_out.microphone_mode.DIALOG_FOLLOW_ON AssistResponse.audio_out AssistResponse.audio_out AssistResponse.audio_out |
gRPC utilizza uno streaming bidirezionale per ricevere i risultati, per ogni chiamata abbiamo la richiesta audio dell’utente (audio_in) e una risposta da parte dell’assistente (audio_out).
Richiesta audio analogica “utterance” che verrà prima convertita in digitale e da cui verrà estratto l’intento dell’utente (lo scopo della frase) da un modulo NLP/NLU. Ad esempio “Mi puoi mostrare la strada per il ristorante cinese? “ ha come intento “trova posizione” invece i dettagli come ristorante cinese saranno le entities.
Feedback visivo
Il nostro intento è di associare un feedback visivo alle richieste dell’utente e alle risposte dell’assistente utilizzando i colori di un led RGB in modo da sapere lo stato della conversazione.
Durante il turno di conversazione dell’utente, quando sta esprimendo una richiesta, associeremo il colore verde [G] e alla risposta dell’assistente il led rosso [R] perché il turno dell’utente è terminato. Infine associeremo il colore blu [B] quando non c’è nessuna interazione fra utente e assistente che rimane in attesa che l’utente prema il pulsante fisico per esprimere una nuova richiesta.
RGB: terna di colori
Un led RGB può riprodurre le lunghezze d’onda dei tre colori di base ([R] rosso, [G] verde, [B] blu) e dalla somma della terna di colori è possibile ottenere il colore bianco [W], mentre dalla loro assenza il nero.
Invece dalla sovrapposizione di due colori:
[R] + [B] = [M] magenta
[R] + [G] = [Y] giallo
[G] + [ B] = [C] ciano
Led RGB
Un led RGB possiede 4 reofori che collegheremo ai pin GPIO-13, GPIO-19 e GPIO-26 della Raspberry e GPIO-22 alla massa.
Le GPIO forniscono una tensione di 3.3v e in ingresso non tollerano i 5v come Arduino quindi per sicurezza inseriremo in serie ad ogni LED un resistore da 220 ohm che consentirà di regolare la corrente circolante nel diodo.
[R] GPIO-13
[G] GPIO-19
[B] GPIO-26
[GND] GND
Utilizzando il servizio gRPC per iniziare la conversazione con Google Assistant dobbiamo premere un pulsante fisico che collegheremo alla GPIO-22
Editare push to talk
Per prima cosa aggiungiamo alla Raspberry il pacchetto RPi.GPIO per il supporto GPIO (porta generica I/O) usando il seguente comando:
1 |
pip install RPi.GPIO |
Modifichiamo il file pushtotalk.py , dopo averne fatto una copia di backup (pushtotalk_orig.py), che se abbiamo seguito questo tutorial si troverà nella cartella site-packages delle librerie per Python.
Aggiungiamo le seguenti righe per il supporto al led RGB e al pulsante.
1 2 3 4 5 6 7 8 9 |
GPIO.setmode(GPIO.BCM) GPIO.setwarnings(False) #leds GPIO.setup(13, GPIO.OUT) #led red 13 out GPIO.setup(19, GPIO.OUT) #led green 19 out GPIO.setup(26, GPIO.OUT) #led blue 26 out #Trigger Pin GPIO.setup(22, GPIO.IN, pull_up_down = GPIO.PUD_UP) |
L’utente sta parlando
All’interno del metodo assist inseriamo le righe di codice inerenti a quando l’utente sta parlando quindi il led verde [G] sarà acceso e i restanti spenti.
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 |
def assist(self): “”“ Send a voice request to the Assistant and playback the response. Returns: True if conversation should continue. ““” continue_conversation = False device_actions_futures = [] self.conversation_stream.start_recording() #led on start conversation, audio input from user GPIO.output(13,GPIO.LOW) #red GPIO.output(19,GPIO.HIGH) #green l’utente sta parlando GPIO.output(26,GPIO.LOW) #blue logging.info(‘Recording audio request.’) |
L’assistente sta rispondendo
Ora dobbiamo associare il led rosso [R] alla risposta dell’assistente che coinciderà con la fine dell’utterance.
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 |
# This generator yields AssistResponse proto messages # received from the gRPC Google Assistant API. for resp in self.assistant.Assist(iter_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 (end of utterance)’) self.conversation_stream.stop_recording() if resp.speech_results: GPIO.output(13,GPIO.HIGH) #red l’assistente sta rispondendo GPIO.output(19,GPIO.LOW) #green GPIO.output(26,GPIO.LOW) #blue logging.info(‘Playing assistant response.’) |
L’assistente è in attesa di una richiesta
Quando l’assistente finisce il turno di conversazione lo mandiamo in modalità di attesa di una richiesta da parte dell’utente.
1 2 3 4 5 |
logging.info(‘Finished playing assistant response.’) #led OFF start conversation GPIO.output(13,GPIO.LOW) GPIO.output(19,GPIO.LOW) GPIO.output(26,GPIO.HIGH) #blue |
Pulsante fisico
Per poter iniziare la conversazione e l’utente esprimere la sua richiesta deve prima poter premere il pulsate fisico. Andremo quindi ad aggiungere all’interno del metodo main le righe per il pulsante.
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 |
wait_for_user_trigger = not once while True: if wait_for_user_trigger: #click.pause(info=’Premi Enter to send a new request…’) button_state=GPIO.input(22) if button_state==True: continue else: print(“Button Pressed”) pass continue_conversation = assistant.assist() # wait for user trigger if there is no follow-up turn in # the conversation. wait_for_user_trigger = not continue_conversation # If we only want one conversation, break. if once and (not continue_conversation): break |
Impostare l’assistente all’avvio
L’idea è che ogni volta che la Raspberry Pi termina il processo di avvio, eseguiremo lo script python che autenticherà e inizializzerà l’Assistente Google. Per farlo editeremo uno script shell a cui daremo il nome assistant-autostart:
1 |
sudo leafpad assistant–autostart.sh |
Al file appena creato aggiungeremo le seguenti righe:
1 2 3 4 |
#!/bin/bash source env/bin/activate googlesamples–assistant–pushtotalk —project–id zeroassistant–196222 —device–model–id ZeroAssistantModel —lang it–IT |
Dopo aver dato i permessi potremmo lanciare Assistant quante volte vogliamo dallo script.
1 |
sudo chmod +x assistant–autostart.sh |
Se volessimo lanciare Assistant all’avvio della Raspberry con il Desktop dovremmo editare il file autostart
1 |
sudo leafpad /home/pi/.config/lxsession/LXDE–pi/autostart |
ed aggiungervi il percorso dello script shell.
1 2 3 4 5 |
@lxpanel —profile LXDE–pi @pcmanfm —desktop —profile LXDE–pi @xscreensaver –no–splash @point–rpi /home/pi/assistant–autostart.sh |
Sitografia
[1] James Schaefer, Smart Devices – What Makes Them “Smart”?, IotForAll, 14/01/2017
[2] Mark Bergen, Google CEO Sets ‘AI-First’ Device Blueprint to Catch Apple, Bloomberg, 04/08/2017
[3] Robert Triggs, What being an “AI first” company means for Google, Android Authority, 08/11/2017
[4] Martin Recke, The AI-First world requires new products, Next Conference, 13/12/2017
Google Assistant Embedded: v1alpha2
[1] Google Assistant Library
[2] Google Assistant Service
[3] EmbeddedAssistant
[4] AssistRequest
[5] AudioOut