Accessibilità per app iOS riconoscimento vocale

Gli sviluppatori sono costantemente impegnati a rendere le proprie app più avanzate, ma sono effettivamente utilizzabili da tutti? Per la maggior parte delle app, la risposta è no. Per raggiungere il pubblico più vasto, impariamo come rendere le nostre app più accessibili. 

In seguito alla Giornata internazionale delle persone con disabilità delle Nazioni Unite, diamo un'occhiata a come possiamo rendere le nostre app iOS più accessibili.

In questo tutorial, utilizzeremo AVAudioEngine per trascrivere il parlato e mostrarlo all'utente come testo (proprio come Siri sul tuo iPhone).

Questo tutorial presume che tu sia esperto in Swift e che tu abbia familiarità con l'uso di Xcode per lo sviluppo di iOS. 

Impostazione del progetto

Per seguire, puoi creare un nuovo progetto in Xcode o scaricare il progetto di esempio per questa app. 

Se stai lavorando da un nuovo progetto, aggiungi la seguente riga all'inizio del tuo ViewController.swift file in modo che l'API vocale venga importata. 

discorso di importazione

Un altro passo che devi compiere prima di iniziare è fare il ViewController () classe conforme al SFSpeechRecognizerDelegate

Una volta fatto, sei pronto per iniziare il tutorial. 

1. Chiedere l'autorizzazione

Dato che Apple prende sul serio la privacy, è logico che richiedano agli sviluppatori di chiedere agli utenti il ​​permesso prima di utilizzare i microfoni del dispositivo, soprattutto perché i dati vengono inviati ai server di Apple per l'analisi.

Nel caso del riconoscimento vocale, è necessaria l'autorizzazione perché i dati vengono trasmessi e memorizzati temporaneamente sui server Apple per aumentare l'accuratezza del riconoscimento.- Documentazione Apple

Nel tuo progetto Xcode, dovrai aprire il tuo Info.plist file e aggiungi due coppie chiave-valore. Ecco le chiavi che puoi incollare in:

  • NSMicrophoneUsageDescription
  • NSSpeechRecognitionUsageDescription

Per i valori, puoi inserire qualsiasi stringa che descriva accuratamente le autorizzazioni desiderate e perché ne avrai bisogno. Questo è come dovrebbe apparire una volta aggiunti:

Ora, dovremo effettivamente chiedere l'autorizzazione all'utente prima di poter procedere. Per fare questo, possiamo semplicemente chiamare un metodo, chiamato convenientemente requestAuthorization ().

Ma prima di farlo, dentro il tuo viewDidLoad () metodo, aggiungi la seguente riga di codice:

microphoneButton.isEnabled = false

Per impostazione predefinita, questo farà sì che il pulsante sia disabilitato, in modo che non ci siano possibilità che l'utente possa premere il pulsante prima che l'app abbia la possibilità di verificare con l'utente. 

Successivamente, dovrai aggiungere la seguente chiamata al metodo:

SFSpeechRecognizer.requestAuthorization (status) in OperationQueue.main.addOperation // Il tuo codice va qui

All'interno del gestore di completamento di questo metodo, stiamo ricevendo lo stato dell'autorizzazione e quindi impostandolo su una costante chiamata stato. Dopodiché, abbiamo una chiamata asincrona che aggiunge il codice all'interno del blocco al thread principale (poiché lo stato del pulsante deve essere modificato nel thread principale).

All'interno del addOperation blocco, dovrai aggiungere quanto segue interruttore dichiarazione per verificare quale sia lo stato di autorizzazione in realtà:

switch status case .authorized: dictationButton.isEnabled = true promptLabel.text = "Tocca il pulsante per iniziare la dettatura ..." predefinito: dictationButton.isEnabled = false promptLabel.text = "Dettatura non autorizzata ..."

Stiamo accendendo il valore di ritorno del authorizationStatus () funzione. Se l'azione è autorizzata (stato è .autorizzato), il pulsante di dettatura è abilitato e Tocca il pulsante per iniziare a dettare ...  È visualizzato. In caso contrario, il pulsante di dettatura è disabilitato e Dettatura non autorizzata ...  È visualizzato.

2. Progettazione dell'interfaccia utente

Successivamente, avremo bisogno di progettare un'interfaccia utente per poter fare due cose: avviare o interrompere la dettatura e visualizzare il testo interpretato. Per fare questo, vai al Main.storyboard file.

Ecco i tre elementi del builder dell'interfaccia che dovrai continuare con questo tutorial:

  • UILabel
  • UITextView
  • UIButton

Dato che il posizionamento non è fondamentale in questa app, non coprirò esattamente dove e come posizionare tutto, quindi segui questo wireframe di base quando inserisci gli elementi dell'interfaccia utente:

Come punto di riferimento, ecco come appare il mio storyboard a questo punto:

Di nuovo, va bene se il layout è diverso, ma assicurati di avere gli stessi tre elementi di base nel wireframe. Ora, incolla le seguenti righe di codice verso la parte superiore del tuo ViewController () classe:

@IBOutlet var promptLabel: UILabel! @IBOutlet var transcribedTextView: UITextView! @IBOutlet var dictationButton: UIButton!

Verso il fondo del ViewController () classe, è sufficiente aggiungere la seguente funzione da attivare quando si tocca il pulsante di dettatura:

@IBAction func dictationButtonTapped () // Il tuo codice va qui

L'ultima cosa che resta da fare è aprire il Assistente editore e connetti le connessioni del generatore di interfacce al tuo Main.storyboard file. I punti che appaiono accanto a loro ora dovrebbero apparire pieni, e ora sarai in grado di accedere a tutti questi elementi come variabili e metodi, rispettivamente.

3. Aggiunta di variabili

Ora siamo finalmente pronti per iniziare il riconoscimento vocale. Il primo passo è creare le variabili e le costanti appropriate che verranno utilizzate durante il processo. Sotto i tuoi connettori di interfaccia, aggiungi le seguenti righe di codice:

let audioEngine = AVAudioEngine () let speechRecognizer = SFSpeechRecognizer (locale: Locale (identificativo: "en-US"))! richiesta var: SFSpeechAudioBufferRecognitionRequest? task var: SFSpeechRecognitionTask?

Ecco una descrizione di cosa fanno le variabili e le costanti:

  • Audioengine è un'istanza di AVAudioEngine () classe. Questa classe è, in termini semplici, una serie di nodi audio. I nodi audio sono usati per fare varie cose con l'audio come la generazione e l'elaborazione.
  • speechRecognizer è un'istanza di SFSpeechRecognizer () classe. Questa classe non riconosce altro che la lingua specificata, in questo caso, l'inglese americano.
  • richiesta è una variabile opzionale di tipo SFSpeechAudioBufferRecognitionRequest, ed è attualmente inizializzato per zero. Più avanti in questo tutorial, creeremo effettivamente uno di questi e imposteremo il suo valore quando avremo bisogno di usarlo. Questo sarà usato per riconoscere i dati di input dal microfono del dispositivo.
  • compito è un'altra variabile opzionale, questa volta di tipo SFSpeechRecognition. Successivamente, utilizzeremo questa variabile per monitorare i progressi del nostro riconoscimento vocale.

Dopo aver aggiunto le variabili, hai tutto ciò che ti serve per immergerti direttamente nel processo di riconoscimento vocale.

4. Dichiarazione del metodo di dettatura

Ora, creeremo il metodo principale per il nostro algoritmo di riconoscimento vocale. Sotto il viewDidLoad () metodo, dichiarare la seguente funzione:

func startDictation () // Il tuo codice va qui

Dal momento che non conosciamo lo stato attuale del compito, dovremo annullare l'attività corrente e, quindi, dobbiamo impostarla su zero (nel caso non lo sia già). Questo può essere fatto aggiungendo le seguenti due righe di codice nel tuo metodo:

task? .cancel () task = nil

Grande! Ora sappiamo che non esiste un'attività già in esecuzione. Questo è un passaggio importante quando si usano variabili dichiarate al di fuori dell'ambito del metodo. Una cosa da notare è che stiamo usando il concatenamento opzionale per chiamare Annulla() sopra compito. Questo è un modo conciso di scrivere che vogliamo solo chiamare Annulla() Se compito non è niente.

5. Inizializzazione delle variabili

Ora, dobbiamo inizializzare le variabili che abbiamo creato in precedenza in questo tutorial. Per procedere, aggiungi queste righe di codice al tuo startDictation () metodo dal passaggio precedente:

request = SFSpeechAudioBufferRecognitionRequest () let audioSession = AVAudioSession.sharedInstance () let inputNode = audioEngine.inputNode guard let request = request else return request.shouldReportPartialResults = true prova? audioSession.setCategory (AVAudioSessionCategoryRecord) provare? audioSession.setMode (AVAudioSessionModeMeasurement) provare? audioSession.setActive (true, con: .notifyOthersOnDeactivation)

Scopriamolo. Ricorda il richiesta variabile che abbiamo creato in precedenza? La prima riga di codice inizializza quella variabile con un'istanza di SFSpeechAudioBufferRecognitionRequest classe. 

Successivamente, assegniamo l'istanza della sessione audio condivisa a una costante chiamata audioSession. La sessione audio si comporta come un intermediario tra l'app e il dispositivo stesso (e i componenti audio).

Dopodiché, impostiamo il nodo di input su un singleton chiamato inputNode. Per iniziare a registrare, in seguito creeremo un rubinetto su questo nodo.

Successivamente, usiamo una guardia per scartare il richiesta variabile che abbiamo inizializzato in precedenza. Questo è semplicemente per evitare di doverlo scartare più avanti nell'applicazione. Quindi abiliteremo la visualizzazione di risultati incompleti. Funziona in modo simile alla dettatura sull'iPhone, se hai mai usato la dettatura, saprai che il sistema digita qualsiasi cosa pensi, e quindi, usando gli indizi del contesto, regola le cose se necessario. 

Infine, le ultime tre righe di codice tentano di impostare vari attributi della sessione audio. Queste operazioni possono generare errori, quindi devono essere contrassegnati con provare? parola chiave. Per risparmiare tempo, ignoreremo tutti gli errori che si verificano. 

Ora abbiamo inizializzato la maggior parte delle variabili che erano precedentemente nello stato zero. Un'ultima variabile da inizializzare è la compito variabile. Lo faremo nel prossimo passaggio.

6. Inizializzazione della variabile di attività

L'inizializzazione di questa variabile richiederà un gestore di completamento. Incolla il seguente codice nella parte inferiore del tuo startDictation () metodo:

task = speechRecognizer.recognitionTask (con: request, resultHandler: (result, error) in guardia lascia result = result else return self.transcribedTextView.text = result.bestTranscription.formattedString if error! = nil || result.isFinal  self.audioEngine.stop () self.request = nil self.task = nil inputNode.removeTap (onBus: 0))

In primo luogo, creiamo a recognitionTask con il richiesta come parametro Il secondo parametro è una chiusura che definisce il gestore di risultati. Il risultato parametro è un'istanza di SFSpeechRecognitionResult. All'interno di questo gestore di completamento, è necessario scartare nuovamente la variabile risultato. 

Successivamente, impostiamo il testo della nostra visualizzazione di testo come la migliore trascrizione che l'algoritmo può fornire. Questo non è necessariamente perfetto, ma è ciò che l'algoritmo pensa sia più adatto a ciò che ha sentito.

Infine, all'interno di questo Se dichiarazione, stiamo prima controllando se c'è un errore, o se il risultato è finalizzato. Se uno di questi è vero, il motore audio e altri processi correlati si fermeranno e rimuoveremo il rubinetto. Non ti preoccupare, imparerai a parlare dei tap nel prossimo passaggio!

7. Avvio del motore audio

Finalmente il momento che stavi aspettando! Finalmente possiamo avviare il motore che abbiamo speso così a lungo nella creazione. Lo faremo installando un "tap". Aggiungi il seguente codice sotto il tuo compito inizializzazione:

let recordingFormat = inputNode.outputFormat (forBus: 0) inputNode.installTap (onBus: 0, bufferSize: 1024, format: recordingFormat) (buffer, when) in self.request? .append (buffer)

In questo codice, impostiamo il formato di output del nodo di input su una costante chiamata recordingFormat. Questo è usato nel passaggio successivo per installare un audio rubinetto sul nodo di input per registrare e monitorare l'audio. All'interno del gestore di completamento, stiamo aggiungendo il buffer in un formato PCM alla fine della richiesta di riconoscimento. Per avviare il motore, aggiungi le seguenti due righe di codice:

audioEngine.prepare () prova? audioEngine.start ()

Questo semplicemente prepara e quindi tenta di avviare il motore audio. Ora, dobbiamo chiamare questo metodo dal nostro pulsante, quindi facciamolo nel prossimo passaggio.

8. Disabilitare e abilitare il pulsante

Non vogliamo che l'utente sia in grado di attivare il riconoscimento vocale a meno che non sia disponibile per essere utilizzato, altrimenti l'app potrebbe bloccarsi. Possiamo farlo attraverso un metodo delegato, quindi aggiungi le seguenti poche righe di codice sotto startDictation () dichiarazione del metodo:

func speechRecognizer (_ speechRecognizer: SFSpeechRecognizer, availabilityDidChange disponibile: Bool) se disponibile dictationButton.isEnabled = true else dictationButton.isEnabled = false

Questo verrà chiamato quando il riconoscimento vocale diventa disponibile dopo essere stato disponibile o non disponibile dopo essere stato disponibile. Al suo interno, utilizzeremo semplicemente un'istruzione if per abilitare o disabilitare il pulsante in base allo stato di disponibilità.

Quando il pulsante è disabilitato, l'utente non vedrà nulla, ma il pulsante non risponderà ai tocchi. Questa è una sorta di rete di sicurezza per impedire all'utente di premere il pulsante troppo velocemente.

9. Rispondere ai pulsanti

L'ultima cosa che resta da fare è rispondere quando l'utente tocca il pulsante. Qui, possiamo anche cambiare ciò che dice il pulsante e dire all'utente cosa devono fare. Per rinfrescare la memoria, ecco il @IBAction abbiamo fatto prima:

@IBAction func dictationButtonTapped () // Il tuo codice va qui

All'interno di questa funzione, aggiungere la seguente istruzione if:

if audioEngine.isRunning dictationButton.setTitle ("Start Recording", per: .normal) promptLabel.text = "Tocca il pulsante per dettare ..." request? .endAudio () audioEngine.stop () else dictationButton.setTitle (" Arresta registrazione ", per: .normal) promptLabel.text =" Procedi. Sto ascoltando ... "startDictation ()

Se il motore audio è già in esecuzione, vogliamo interrompere il riconoscimento vocale e visualizzare il prompt appropriato all'utente. Se non è in esecuzione, è necessario avviare il riconoscimento e visualizzare le opzioni per l'utente per interrompere la dettatura.

Conclusione

Questo è tutto! Hai creato un'applicazione in grado di riconoscere la tua voce e trascriverla. Questo può essere utilizzato per una varietà di applicazioni al fine di aiutare gli utenti che non sono in grado di interagire con le tue app in altri modi. Se ti è piaciuto questo tutorial, assicurati di dare un'occhiata agli altri di questa serie!

E mentre sei qui, controlla alcuni dei nostri altri post sullo sviluppo di app Swift e iOS!