Gli assistenti vocali stanno piano piano entrando nelle nostre vite, Google Home, Alexa, Siri, Google Assistant.. Sta diventando “normale” chiedergli informazioni usando solo la nostra voce e attendere la loro risposta , sempre a voce.
Ma come è possibile tutto questo? Il riconoscimento vocale da parte di computer si studia dagli anni ’50, ma solo ultimamente, grazie alle evoluzioni delle IA, si è arrivati ad avere un riconoscimento del linguaggio naturale alla portata di tutti. La sintesi vocale (cioè quando invece il computer pronuncia delle parole) è arrivata alla diffusione di massa solo poco prima.
E Python?
E’ possibile fare tutto questo (riconoscimento vocale e sintesi vocale) con Python? Si, certo. In programmazione quasi ogni cosa è possibile, e la potenza di Python e la sua flessibilità nell’uso delle librerie, lo rende possibile in meno di 50 righe. Oppure, si può creare una rete neurale che comprenda i singoli lemmi di quel che pronunciate… Ma no, non preoccupatevi! Oggi vediamo la soluzione più semplice: ci appoggeremo a delle librerie che faranno per noi il lavoro complicato. Ci occuperemo solo di acquisire quel che viene detto al programma, e di dare una risposta vocale. la logica (o “intelligenza”) che sta nel mezzo, per cui la risposta debba essere più o meno coerente con l’input, esula da questa guida. Gli assistenti vocali citati sopra hanno una IA e il supporto della rete per elaborare una risposta coerente, noi possiamo creare un dizionario di risposte per rispondere in rima, o dare risposte preimpostate, o semplicemente sostituire input e output di qualsiasi programma con le loro controparti vocali.
Libreria di riconoscimento
Dopo i primi tentativi un po’ grossolani, ho scoperto che esistono molte librerie Python dedicate al riconoscimento vocale e in questa guida useremo SpeechRecognition che, nonostante il nome poco originale, mi è sembrata abbastanza pratica da usare.
Il problema del microfono
C’è un problemino non indifferente: Nessun modello di Raspberry Pi è dotato di microfono di serie. Difficile farsi “ascoltare”; quindi. Occorre collegare un microfono. Ci sono modelli USB, o mini schede audio USB con jack di uscita e ingresso microfonico. In alternativa, alcune webcam sono dotate di microfono, anche se non in tutte, questo viene riconosciuto su Linux/Raspberry Pi. O, molto più facile da mettere in pratica, probabilmente, è usare delle cuffie con microfono, cablate o Bluetooth, sono comode per testare e affinare il programma, ma probabilmente non adatte alla vostra installazione definitiva. Il programma cerca il microfono di sistema (indirizzo 0), ma può essere che microfoni aggiunti vengano indicizzati con altri indirizzi (o nel caso abbiate addirittura più di un microfono). più avanti vedremo come fare.
Non esiste quindi qui una indicazione univoca: la mia cuffia con microfono Bluetooth, ad esempio, viene riconosciuta solo come cuffia da Debian Buster, mentre nella webcam, sono riconosciuti 2 microfoni (canale destro e canale sinistro; ha microfono stereofonico).
Libreria di sintesi vocale
Per far parlare il nostro Raspberry Pi, in italiano, ho scelto di usare il TTS (Text To Speech) di Google. Anche qui, dopo i primi tentativi di usare la pagina web di google traduttore che prevede di ascoltare la pronuncia, ho trovato una libreria che lo fa per noi: gtts (Google TTS). Ne esistono moltissime, ho scelto di usare Google per l’unione di qualità e semplicità, che ben si adattano a una guida come questa. Segnalo anche OpenTTS, con il quale è possibile installare un server di sintesi TTS in locale, che si può utilizzare, quindi, anche senza il collegamento alla rete. Ci servirà poi un metodo per riprodurre il suono creato. Normalmente la strada regolare sarebbe usare a libreria playsound che servirà a… Indovinate un po’? Si, a riprodurre un suono (non si può dire che i nomi delle librerie attingano alla fantasia, ma perlomeno la loro funzione è chiara anche dal nome).
Ma in realtà il sottosistema audio su Linux può essere parecchio complesso (PyAudio, ALSA / JuiceAudio…) . Per il nostro caso, la soluzione più semplice è semplicemente usare un player audio a linea di comando.
Installare le librerie
Ora, visto che nel 2022 non ha più senso usare Python 2.x, useremo il 3, giusto per abituarci. Le librerie le possiamo installare con il classico
1 |
pip3 install nomelibreria |
digitato sul Terminale. E va benissimo, ma oggi voglio approfittare di questa guida anche per mostrarvi una comoda funzione di Thonny (il programma IDE, preinstallato su Raspberry Pi OS, che useremo per scrivere il nostro script Python). Apriamolo, quindi (Menù lampone – Programmazione – Thonny Python IDE).
Thonny
Una volta in Thonny, scegliete menù strumenti – gestisci pacchetti. Si apre un pannello tramite il quale si possono cercare e installare i componenti aggiuntivi, come le nostre librerie. Perché è comodo? Perché ti permette di trovare le librerie anche se non ne conosci il nome preciso, perché le trova per diversi sistemi (esempio micropython per Raspberry Pi Pico e altri microcontrollori) e perché farlo da interfaccia grafica è più user-friendly, si può avere una descrizione prima di installarle.
Cerchiamo
Cerchiamo quindi SpeechRecognition nella barra in alto, e troviamo “SpeechRecognition – Library for performing speech recognition, with support for several engines and APIs, online and offline.” CI permette di usare infatti molti motori per il riconoscimento o di appoggiarci a delle API di servizi online, in modo da essere versatile (con il supporto a moltissime lingue). Selezioniamola e installiamola.
Ora cerchiamo gtts e procediamo nello stesso modo.
E’ arrivato ora il momento del player audio. Ho usato mpg123 che dovrebbe essere pre-installato. Nel caso così non fosse nella vostra distribuzione, dal Terminale digitate:
1 |
sudo apt install mpg123 |
Si possono usare anche altri player a scelta.
Prima Parte: Riconoscimento Vocale
Cominciamo a scrivere del codice.
1 2 3 4 5 6 7 8 9 10 11 12 |
import speech_recognition as sp #importo la libreria r = sp.Recognizer() #r ora significa 'speech_recognition.Recognizer()' with sp.Microphone() as source: #with sp.Microphone(device_index=6) as source: #index= indirizzo del mic r.adjust_for_ambient_noise(source,duration=1) audio = r.listen(source) result = "" try: result = r.recognize_google(audio,language='it') print(result) except Exception as e: print("non ho capito") |
Descrizione
Un semplice esempio di riconoscimento vocale con speech recognition. Cominciamo importando la libreria, dandogli un alias più breve (sp). Affidiamo la classe sp.Recognizer() a una variabile, qui r, sempre per brevità di scrittura del codice. Poi gli diciamo di utilizzare il microfono come sorgente. Come detto, un dei principali scogli è trovare l’indirizzo del microfono che avremo collegato a Raspberry Pi . with sp.Microphone() as source: userà il microfono con indirizzo 0, questo va bene sui computer portatili, che hanno un microfono integrato, ma non va altrettanto bene con Raspberry Pi. Meglio usare la formula with sp.Microphone(device_index=x) as source: dove x è un numero da 0 a 10 che è l’indirizzo fisico del microfono. Se non lo conoscete potete andare a tentativi, oppure ecco un piccolo script che cerca i dispositivi audio di input per voi, con i loro ID. Richiede di avere installata la libreria pyaudio, se non ci fosse, installatela come descritto su per le altre librerie.
1 2 3 4 5 6 7 |
import pyaudio p = pyaudio.PyAudio() info = p.get_host_api_info_by_index(0) numdevices = info.get('deviceCount') for i in range(0, numdevices): if (p.get_device_info_by_host_api_device_index(0, i).get('maxInputChannels')) > 0: print ("Input Device id ", i, " - ", p.get_device_info_by_host_api_device_index(0, i).get('name')) |
Per la mia webcam ha trovato due id: il 6 (pulse) e il 10 (default). Funziona con entrambi (ha il microfono stereofonico).
Proseguiamo con l’analisi del codice: nelle righe seguenti adjust_for_ambient_noise cerca di calibrare il microfono in base al rumore ambientale, ascoltandolo per 1 secondo (modificare il valore in caso di rumorosità ambientale particolare). Con audio = r.listen(source) ci si mette di ascolto per una frase.
Poi passiamo quanto ascoltato a Google, per il riconoscimento del parlato in italiano. La IA specializzata in linguaggio naturale di Google farà il suo lavoro, e fornirà un risultato (result) testuale che è la trascrizione di quanto ascoltato. Nel caso non ci riuscisse per qualsiasi motivo, il programma ci avviserà con un “non ho capito”.
Rendiamolo “funzionale”
Ora, per comodità di utilizzo all’interno di altri programmi, trasformiamolo in una funzione, in modo da richiamarla e avere un risultato da essa (il testo del parlato “ascoltato”). Per comprendere cosa è una funzione, l’esempio classico è print. In realtà print non è un comando Python, ma una funzione “di serie” in Python che permette di scrivere a schermo quello che le passiamo come argomento. Noi ora creeremo la nostra funzione get_audio che potremo lanciare all’interno di programmi così come facciamo con print.
Il listato quindi diventerà
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 |
import speech_recognition as sp def get_audio(): r = sp.Recognizer() with sp.Microphone() as source: r.adjust_for_ambient_noise(source,duration=1) audio = r.listen(source) result = "" try: result = r.recognize_google(audio,language='it') except Exception: print("non ho capito") return result output = get_audio() print (output) |
Questo programma ascolta una sola frase, per riprovare, occorre lanciarlo nuovamente. Provateci, è divertente!
Non preoccupatevi, per ora, se vedete molte scritte sulla console Python, è normale. Poi troveremo una soluzone.
Seconda Parte: Sintesi Vocale
Se con la prima parte ce la siamo cavata con l’aiuto di Google, in questa seconda come possiamo fare? Chiedendo ancora aiuto a Google, naturalmente! Qui useremo la libreria gtts. Definiamo quindi una nuova funzione che accetti un argomento (una stringa di testo) e la possa trasformare in un suono (l’audio che pronuncia quel testo)
1 2 3 4 5 6 7 8 9 10 11 12 |
from gtts import gTTS import subprocess def speak(text): tts =gTTS(text=text,lang='it') filename = "voce.mp3" if os.path.exists(filename): os.remove(filename) tts.save(filename) subprocess.run(['mpg123', '-g', 'voce.mp3']) speak ("Riesci a sentirmi?") |
Descrizione
Importiamo la classe gTTS dalla libreria gtts per usare l’algoritmo Text To Speech di Google, e la libreria subprocess, che useremo pere lanciare un programma Linux da dentro Python, il nostro player audio (in questa guida, mpg123). Definiamo la nostra funzione, che chiamiamo speak, perché serve a far parlare il nostro programma, e gli impostiamo un argomento che possa accettare in ingresso, lo ho chiamiamo text, perché sarà il nostro testo da trasformare in parlato.
Chiamiamo tts una variabile in cui mettere il risultato che produrrà gTTS che qui impostiamo per processare quanto passato alla funzione (text) tenendo conto del linguaggio italiano. In filename mettiamo il nome (o il percorso completo) del file audio che useremo come appoggio, verifichiamo poi se già esiste, nel qual caso lo cancelliamo, poi andiamo a salvare tts con il nome filename.
A questo punto, finalmente, potremo lanciare il player mpg123 per riprodurre il file voce.mp3, grazie a subprocess. Richiamando la funzione, passando come argomento una stringa di testo, dovremmo sentirlo ora pronunciato, un po’ come quando richiamiamo print, poi vediamo il testo stampato a video.
Terza Parte: Mettiamo tutto insieme
Ora abbiamo creato una funzione che ascolta il microfono e riesce a tradurre il parlato in una stringa di testo; un’altra che, data una stringa di testo, riesce a tradurla in parlato. Abbiamo quindi un input e un output, entrambi vocali. Possiamo creare, con esse, un programma, che “ascolti” quel che diciamo e ci risponda, parlando!
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 |
import speech_recognition as sp import os, subprocess from gtts import gTTS from random import randrange from time import sleep saluti_in = ["ciao","ciao python","hei","buongiorno","come stai?","ci sei","bentrovato"] saluti_out = ["hei","come va?","salve!","dimmi","eccomi","ciao Mauro","benvenuto","sono pronto","o mio padrone, ogni tuo desiderio è un ordine"] uscita_in = ["addio","esci"] clearConsole = lambda: print('\n' * 150) #definiamo le funzioni def get_audio(): r = sp.Recognizer() with sp.Microphone(device_index=10) as source: #il device index del vostro microfono clearConsole() #pulisce lo schermo print("in ascolto...") r.adjust_for_ambient_noise(source,duration=1) audio = r.listen(source) result = "" try: result = r.recognize_google(audio,language='it') except Exception: print("non ho capito") sleep (1) #attesa di un secondo return result def speak(text): tts =gTTS(text=text,lang='it') filename = "voce.mp3" if os.path.exists(filename): os.remove(filename) tts.save(filename) subprocess.run(['mpg123', '-q', 'voce.mp3'], stderr=subprocess.DEVNULL) #disabilita messaggi di errore #main while True: #ciclo infinito text_in = get_audio() #ascolta una frase traducila con get_audio() e mettila in text_in text_in = text_in.lower() #porta tutto minuscolo text_out = text_in if text_in!=None and text_in!="": if text_in in saluti_in: #se il testo riconosciuto corrisponde a uno dei ran = randrange(len(saluti_out)) #.. saluti_in, risponde con un saluto a caso tra i text_out = saluti_out[ran] #.. saluti_out, altrimenti ripete a pappagallo if text_in in uscita_in: #se riconosce una delle parole chiave di uscita print("a presto") #saluta e esce quit() print(text_out) speak(text_out) |
In questo esempio, potrete parlare al vostro script Python, che vi risponderà a voce alta. Se lo saluterete, lui risponderà al saluto, altrimenti ripeterà quel che ha capito. Pronunciando “addio” o “esci”, il programma terminerà.
Descrizione
Innanzitutto importiamo le librerie necessarie; in aggiunta a prima c’è randrange importata da random, che ci consentirà di scegliere una risposta casuale tra quelle elencate e sleep, importata da time, per mettere una pausa in modo da leggere il messaggio di errore prima di cancellare la console.
Subito dopo, definiamo, infatti, delle piccole frasi, raccolte in delle liste. Saluti_in è la lista delle frasi che, se riconosciute, fanno capire al programma che quello in ingresso è un saluto. Saluti_out è una lista di saluti che il programma userà per rispondere a un saluto, quando ne riconosce uno (cambiate “Mauro” nel vostro nome, se volete che il programma vi chiami per nome). Uscita_in sono le parole chiave per dire al programma di terminarsi e uscire.
ClearConsole è un sistema che useremo per pulire l’output da tutte le scritte del sistema audio di Linux. Molto “barbaramente”, stampa 150 linee vuote, quando viene richiamato con clearConsole()
Proseguiamo definendo le funzioni viste prima: get_audio() per catturare dell’audio e tradurlo in testo (ricordatevi qui di impostare il corretto indirizzo del microfono) e speak(text) per far pronunciare quello che vogliamo (in questo caso, le risposte da dare)
in #main il programma vero e proprio: dopo aver avvisato che è in ascolto, c’è un ciclo infinito (while True:) che cattura il testo con get_audio, lo porta tutto in minuscolo. Imposta poi la frase in uscita uguale a quella in entrata.. Tranne nel caso in cui questa venga riconosciuta come presente nelle liste con suffisso -in (ingresso). Perché, in questo caso, la frase di uscita viene scelta a caso tra i saluti-out se la frase in ingresso viene riconosciuta come saluto, mentre se viene riconosciuta come una delle parole chiave di uscita_in, il programma viene interrotto.
Se mettiamo il player mpg123.exe (per pc) nella stessa cartella dello script, funzionerà senza modifiche anche su Windows.
Prospettive
E’ solo un piccolo esempio, di nessuna utilità, se non quella di testare quanto appena discusso. Può però suscitare meraviglia, e- soprattutto – far capire come può essere semplice aggiungere una vera e propria interfaccia vocale ai propri programmi. Si può impostare una frase che se riconosciuta esegua una funzione, lanci un comando, magari che vada a recuperare un dato dalla rete (“che tempo c’è?”) e così va.
Oppure potete integrare queste semplici funzioni nei vostri programmi già esistenti, per sostituire o affiancare gli input e output già presenti, per dargli un tocco di modernità con input e feedback vocali. Ricordo che io ho scelto di usare Google per entrambe le funzioni per avere un risultato qualitativamente alto con pochissimo sforzo, sfruttando la loro IA di per il riconoscimento del linguaggio naturale e l’ottimo sintetizzatore vocale di cui dispongono. Ma se si vuole realizzare un progetto sconnesso dalla rete, si può fare tutto in locale: OpenTTS per la sintesi vocale e SpeechRecognition con un motore offline, sono due buoni punti per partire.
A presto, e nel frattempo, chiacchierate con il vostro Python!
Se avete dubbi o sviluppi su questo tutorial, parliamone nella discussione dedicata sul forum.
Se vuoi restare aggiornato, seguici anche sui nostri social: Facebook, Twitter, Youtube
Se vuoi anche trovare prodotti e accessori Raspberry Pi in offerta, seguici anche su Telegram!!