Blazor & Speech to Text

Per un grosso progetto recentemente ho dovuto affrontare un problema solo in evidenza semplice: il riconoscimento vocale (più pomposamente: implementare uno Speech to Text).

In questo post descriverò le varie opzioni possibili per affrontare una funzionalità del genere in Blazor: spero che le mie valutazioni possano aiutare anche altri, evitandogli le strade cieche che ho intrapreso all’inizio delle mie ricerche.

Azure e Speech service

La prima soluzione che ho esplorato è l’utilizzo dei servizi Azure Speech Service: in passato li ho usati in altri progetti con discreta soddisfazione.

Qui però il progetto riguardava Blazor, e con il “nostro” è tutta un’altra storia.

La prima idea è stata quella di usare l’SDK dedicato allo scopo, chiamato Microsoft.CognitiveServices.Speech.

L’idea sembra efficace, ma ci si scontra subito con la dura realtà: alla data attuale NON è compatibile con Blazor WASM, ma solo con Blazor Server.

Siccome il progetto di cui sto parlando è guardacaso basato su Blazor WASM questa strada NON è risultata percorribile.

Oss.: Purtroppo esistono in rete diversi articoli che mostrano come usare Microsoft.CognitiveServices.Speech con Blazor WASM: la dura realtà è che NON funzionerà mai per incompatibilità. Non perdeteci nemmeno tempo.

In un caso come questo abbiamo due possibili soluzioni: usare la versione per javascript (Speech SDK for JavaScript), facilmente utilizzabile anche da Blazor WASM, oppure registrare il vocale per poi mandarlo via REST a un nostro endpoint, che userà a sua volta l’SDK Microsoft.CognitiveServices.Speech.

Mi piaceva molto affrontare la soluzione in questo modo anche perchè magari potevo, lato server, fare pre-elaborazioni sul file audio ricevuto (verificare volume ? minimizzare disturbi ?).

Per tentare di usare questa soluzione ho usato AudioRecorder (vedi linkografia), che permette con poche chiamate di mettere su un sistema di registrazione audio.

Questo usa le API MediaRecorder messe a disposizione dal browser via javascript.

Purtroppo anche questo si è rivelato una strada cieca (almeno per i miei gusti): alla data attuale le registrazioni eseguite con questo sistema forniscono file con formato webm.

Più in generale è proprio l’API MediaRecorder fornisce file audio con questo formato.

Purtroppo, però, l’SDK Microsoft.CognitiveServices.Speech accetta solo file audio in formato wav, e trasformare un file in formato webm in formato wav non è proprio banale.

Per esempio l’eseguibile FFMPeg converte egregiamente tra i due formati, ma non esiste una possibilità, secondo me, semplice di integrarlo in un progetto DotNetCore.

A dire il vero esiste un’interessante libreria che può essere usata allo scopo FFMpegCore (vedi linkografia) che però non è niente altro che un wrapper che alla fine esegue l’exe.

Non so: probabilmente funziona alla grande, ma siccome la parte di backend è in hosting su Azure ho pensato che non fosse cosa agevole usare una soluzione di questo genere.

Da mie ricerche non ho trovato altre librerie usabili da DotNet per fare un’operazione di questo genere.

Oss.: A dire il vero ne ho trovato una commerciale, che però per diverse ragioni non mi ha convinto.

Un’altra possibile soluzione, che non ho però usato, ma ve la riporto qui per completezza, e usare una della diverse librerie javascript (ve ne sono diverse) in grado di trasformare il formato webm in formato wav, e quindi inviare il file risultante lato server.

Come sapere in Blazor è possibile facilemente usare javascript, e questa è una possibile soluzione certamente valida, che però ho preferito scartare in favore di altre.

Riporto, sempre per completezza, il fatto che una variante di quanto presentato potrebbe essere l’invio del file audio via REST direttamente da Blazor WASM verso l’endpoint messo a disposizione dai servizi Azure Speech Service, che al termine restituiscono il testo.

Però anche qui abbiamo sempre il problema che tra i formati accettati non c’è webm.

Spero che in futuro questa mancanza (o almeno io la valuto così) sia colmata, ma questa è la soluzione attuale.

JavaScript Speech Recognition

Questa è la soluzione che usato alla fine: le API utilizzabili da Javascript hanno già il riconoscimento vocale tramite l’uso delle chiamate a SpeechRecognition.

Usare questa libreria javascript da Blazor è veramente banale: come sapete Blazor e javascript coesistono in modo meraviglioso.

Dopo test e ritest mi sono reso conto della bontà della soluzione: il riconoscimento è preciso ed è inutile usare altri strumenti secondo il mio parere (o comunque per l’ambito di utilizzo dell’applicativo in parola).

Inoltre da genovese il fatto di non spendere soldini per usare un servizio Azure a pagamento mi ha totalmente convinto.

Osservo una cosa importante: in Chrome (non so con gli altri browser ma penso sia uguale) questa API usa una serie di chiamate remote, per cui l’applicativo Blazor WASM in parola dovrà sempre essere connesso, ma per l’ambito di utilizzo del progetto non ho trovato caratteristica questa come una limitazione.

Dopo aver utilizzato le API da Blazor usando chiamate a codice javascript (via javainterop), mi sono accorto che esistono un paio di librerie dedicate a Blazor WASM, e che semplificano non poco la cosa.

Ve le riporto in linkografia: le ho usate entrambe e sono entrambe fantastiche.

Un saluto a tutti !!!

Linkografia
Azure Speech service documentation
Nuget: Microsoft.CognitiveServices.Speech
Cognitive Services Speech SDK for JavaScript
GitHub: AudioRecorder
Wikipedia: WebM
FFMpeg
GitHub: FFMpegCore
MDN: SpeechRecognition
NuGet: Blazor.SpeechRecognition.WebAssembly
GitHub: Toolbelt.Blazor.SpeechRecognition