Alexa, apri la dispensa!
Gestione delle scorte di casa con comandi vocali.
Istruzioni per realizzare una skill Alexa.
Nel precedente post, avevamo visto come realizzare un sistema per una gestione più razionale e sostenibile delle scorte domestiche.
In pratica, tramite un semplice barcode reader, un programma e un server per salvare l'elenco dei prodotti che si acquistano, è diventato un gioco da ragazzi tenere sotto controllo tutto quello che quotidianamente utilizziamo in casa e che vale la pena controllare per evitare aquisti inutili o dimenticarsi di qualcosa.
Qualcuno può pensare: va bene, interessante, ma come fare per renderlo ancora più semplice e family friendly?
Serve per forza di cose impugnare un barcode reader e scansionare ogni prodotto che preleviamo quotidianamente dalla dispensa?
La risposta è ovviamente NO. E qui ci sono tutte le istruzioni per far sì che sia Alexa a impartire i comandi al nostro database!
Sommario
1) Architettura di alto livello
- Un database per la memorizzazione dei prodotti e delle relative quantità
- Un barcode reader per la scansione dei barcode dei prodotti in ingresso, ovvero gli acquisti effettuati con la spesa (non più indispensabile in questo progetto)
- Il programma scritto in Python che contiene la logica e le interfacce per la scrittura dei dati nel DB
2) Amazon Simple Queue Service
3) Alexa skill overview
4) Alexa catalog e slot management.
- Creazione del catalogo in formato JSON localmente sul server locale a casa
- Creazione della definizione del catalogo a livello della skill Alexa
- Creazione di una versione del catalogo
- Aggiornamento della configurazione JSON della skill Alexa per recepire la nuova versione
Creazione del catalogo in formato JSON
{ | |
"values": | |
[ | |
{ | |
"id": "8004263667118", | |
"name": { | |
"value": "Aceto di vino decolorato" | |
} | |
}, | |
{ | |
"id": "80752431", | |
"name": { | |
"value": "Aceto balsamico di Modena" | |
} | |
}, ... { ... } ] } |
}
Da notare che è possibile assegnare un id al nome dello slot. Associando il relativo barcode al valore del id, abbiamo quindi la possibilità di associare automaticamente il barcode al prodotto specificato via voce.
Ovviamente questa lista non vogliamo farla manualmente, ma la vogliamo creare automaticamente partendo dal database esistente.
In python l'elenco di cui sopra si traduce infatti nello scrivere un dizionario con un'unica coppia chiave valore del tipo:
dove products rappresenta a sua volta una lista con l'elenco completo dei prodotti del DB. Ogni elemento di questa lista è a sua volta strutturato come un dizionario con unica coppia chiave/valore del tipo:
Il programma importa il modulo createJson che avrà al suo interno:
- una classe Database() che si occupa di gestire la connessione e le esecuzioni delle query sul DB
- una funzione catalog() che utilizzerà l'oggetto Database e utilizzerà i record estratti per formattare il file del catalogo
Il fileJson.json precedentemente creato è un nome temporaneo. Viene poi spostato, con nome products.json, nella cartella definitiva dove il file precedente viene sostituito e archiviato:
Creazione del catalogo
{ "catalogId": "amzn1.ask.interactionModel.catalog.fdee74xx-xxxx-xxxx-xxxx-xxxxxxxx8d"
}
- CatalogAutoRefresh
}
pi@raspberrypi:~/dispensa $ more CatalogAutoRefresh.json
{
"vendorId": "<YOUR-VENDOR-ID>","jobDefinition": {
"type": "CatalogAutoRefresh",
"resource": {
"type": "Catalog",
"id": "<YOUR-CATALOG-ID>"
},
"trigger": {
"type": "Scheduled",
"hour": 0
},
"status": "ENABLED"
}
}
- ReferenceVersionUpdate
Con questo job, l'interaction model della skill recepirà la modifica.
Crea quindi un legame tra l'aggiornamento del catalogo effettuato al passo precedente e la skill. Ovvero fa automaticamente quanto fatto manualmente poco fa.
pi@raspberrypi:~/dispensa $ ask smapi create-job-definition-for-interaction-model --job-definition "file:./ReferenceVersionUpdate.json"
{
"jobDefinition": {
"type": "ReferenceVersionUpdate",
"resource": {
"type": "InteractionModel",
"locales": ["it-IT"],
"id": "<YOUR-SKILL-ID>"
},
"references": [{
"type": "Catalog",
"id": "<YOUR-CATALOG-ID>"
}],
"trigger": {
"type": "ReferencedResourceJobsComplete"
},
"publishToLive": false,
"status": "ENABLED"
}
}
Approfondimenti:
https://developer.amazon.com/en-US/blogs/alexa/alexa-skills-kit/2020/09/automatic-updates-for-reference-based-catalogs
5) Implementazione AWS Lambda function
In questo modo, potremmo conservare i dati relativi agli utenti che useranno lo skill, così da creare delle statistiche legate all'utilizzo e fornire una classifica.
Questo permette anche di personalizzare le risposte che Alexa fornirà in funzione di chi sta utilizzando l'applicazione.
class LaunchRequestHandler
- La prima classe LaunchRequestHandler è quella eseguita al lancio della skill
- Questa si occuperà del messaggio di benvenuto, di inizializzare gli attributi di sessione che memorizzare i dati legati alla singola esecuzione della skill
class RemoveIntentHandler
- Questa classe viene richiamata quando ad Alexa diciamo di aver prelevato un determinato prodotto dalla dispensa.
- Verifica il nome e, nel caso ne esistano più di uno simile, chiede conferma all'utente.
- Invia prodotto e relativa quantità da rimuovere al servizio SQS.
- Avvisa l'utente del completamento dell'azione richiesta e eventualmente fornisce qualche indicazione sul relativo posizionamento in classifica o qualche messaggio personalizzato
class AddIntentHandler
- Come la precedente, ma in questo caso serve per aggiungere un prodotto in dispensa
class StatusIntentHandler
- La classe si differenzia dalle due precedenti, perchè in questo caso non vengono effettuate azioni sul database dei prodotti, ma viene fornita in real time la quantità disponibile di un determinato prodotto
- Il dato viene letto dal bucket S3 che è sempre aggiornato rispetto a quanto presente nel DB di casa
- Questa funzione è utile quando si vuole sapere sia la quantità di un determinato prodotto (es.: aceto bianco marca X, marca Y, ecc.) che di un'intera tipologia di prodotti (es.: aceto bianco)
funzioni generiche
check_PersonID
- Verifica che l'utente in questione sia tra quelli riconosciuti e validi per il salvataggio delle statistiche di utilizzo
- Viene personalizzato il messaggio di benvenuto
- Viene incrementato il contatore di utilizzo dell'applicazione per l'utente
verify_input
- Il codice verificherà che il nome del prodotto fornito dall'utente sia uno di quelli possibili.
- Nel caso il nome non rientri tra quelli definiti, il codice chiamante "solleciterà" un nome corretto tramite la ElicitSlotDirective.
check_other_slot_values
- verifica se ci sono altri valori che contengono il nome del prodotto
- per esempio se viene chiesto aceto bianco, e ci sono due valori aceto bianco marca X e aceto bianco marca Y, verrà richiesto all'utente di confermare: aceto bianco marca X e aceto bianco marca Y.
- Nel caso di utilizzo dell'intent per il check dello stato attuale di un determinato prodotto (StatusIntentHandler) e viene fornito un valore comune a più prodotti (es.: aceto bianco) potrà essere confermato anche il valore iniziale e in tal caso il sistema calcolerà il totale dei singoli prodotti
- Se invece viene richiesto direttamente un valore univoco (es. aceto bianco X o Y), non sarà richiesto di confermare nulla.
confirm_product
- Nel caso a seguito dei passaggi precedenti sia stato scelto o confermato un nome di prodotto, il valore fornito viene immagazzinato in uno slot dedicato (ConfirmedProduct)
- Questa funzione fa sì che il codice utilizzi proprio questo nome come nome definitivo del prodotto
get_authenticated
- Questa funzione è responsabile dell'autenticazione affinchè il codice possa fare uso delle risorse AWS create (SQS, S3)
- Vengono acquisite credenziali temporanee tramite AWS STS (Security Token Service)
send_to_sqs
- grazie a questa funzione, sia la classe di aggiunta che di rimozione prodotti, possono inviare i dati corrispondenti sulla coda (AlexaMovementsQueue.fifo)
check_quantity
- abbiamo visto in precedenza che utilizzando il database dei prodotti su S3, è possibile calcolare la quantità attuale di un determinato prodotto oppure la somma di prodotti simili
ranking
- questa funzione si occupa della costruzione del messaggio finale verso l'utente
- viene letta la tabella delle statistiche di utilizzo e fornito un messaggio personalizzato in funzione del posto in classifica
- i messaggi non sono sempre uguali, ma per renderli più interessanti, vengono scelti casualmente
- inoltre questa lettura personalizzata non viene letta sempre, ma solo a intervalli di alcuni giorni, per evitare che diventi troppo ripetitiva
- l'obiettivo è che l'utilizzatore sia incentivato ad usare la skill
6) Aggiornamento DB dei prodotti gestiti con Alexa
- Utilizzare AWS SDK per Python (Boto3) per gestire i servizi AWS (in questo caso la coda SQS)
- Immagazzinare il risultato della lettura della coda in una variabile response
- Come tipo di variabile questa sarà un dizionario e quindi "navigabile". Esempio:
Commenti
Posta un commento