Ontwikkelaars streven er voortdurend naar om hun apps geavanceerder te maken, maar zijn ze eigenlijk bruikbaar voor iedereen? Voor de meeste apps is het antwoord nee. Laten we leren hoe we onze apps toegankelijker kunnen maken om het grootste publiek te bereiken.
Naar aanleiding van de Internationale Dag van de Verenigde Naties van personen met een handicap, laten we eens kijken hoe we onze iOS-apps toegankelijker kunnen maken.
In deze zelfstudie gebruiken we AVAudioEngine om spraak te transcriberen en weer te geven aan de gebruiker als tekst (net zoals Siri dat doet op uw iPhone).
Deze tutorial veronderstelt dat je bekwaam bent in Swift en dat je bekend bent met het gebruik van Xcode voor iOS-ontwikkeling.
Om mee te gaan, kunt u een nieuw project in Xcode maken of het voorbeeldproject voor deze app downloaden.
Als u met een nieuw project werkt, voegt u de volgende regel toe aan de bovenkant van uw ViewController.swift bestand zodat de spraak-API wordt geïmporteerd.
Spraak importeren
Een andere stap die u moet nemen voordat u begint, is het maken van de ViewController ()
klasse conform de SFSpeechRecognizerDelegate
.
Zodra dat is gebeurd, bent u klaar om de zelfstudie te starten.
Aangezien Apple privacy serieus neemt, is het logisch dat zij ontwikkelaars vragen toestemming te vragen voordat ze de microfoons van het apparaat gebruiken, vooral omdat de gegevens voor analyse naar de servers van Apple worden verzonden.
In het geval van spraakherkenning is toestemming vereist omdat gegevens worden verzonden en tijdelijk worden opgeslagen op de servers van Apple om de nauwkeurigheid van herkenning te vergroten.- Apple Documentation
In uw Xcode-project moet u uw. Openen Info.plist bestand en voeg twee sleutel / waarde-paren toe. Hier zijn de sleutels die u kunt in plakken:
NSMicrophoneUsageDescription
NSSpeechRecognitionUsageDescription
Voor de waarden kunt u elke tekenreeks invoeren die nauwkeurig de gewenste machtigingen beschrijft en waarom u deze nodig hebt. Dit is hoe het eruit zou moeten zien als ze eenmaal zijn toegevoegd:
Nu moeten we de gebruiker om toestemming vragen voordat we verder kunnen gaan. Om dit te doen, kunnen we gewoon een methode noemen, die handig wordt genoemd requestAuthorization ()
.
Maar voordat we dat doen, binnenin je viewDidLoad ()
methode, voeg de volgende regel code toe:
microphoneButton.isEnabled = false
Standaard wordt hierdoor de knop uitgeschakeld, zodat er geen kans is dat de gebruiker op de knop drukt voordat de app de gelegenheid heeft om met de gebruiker te overleggen.
Vervolgens moet u de volgende methodeaanroep toevoegen:
SFSpeechRecognizer.requestAuthorization (status) in OperationQueue.main.addOperation // Uw code wordt hier weergegeven
Binnen de voltooiingshandler van deze methode ontvangen we de status van de autorisatie en stellen deze vervolgens in op een constante call staat
. Hierna hebben we een asynchrone aanroep die de code in het blok toevoegt aan de hoofdthread (aangezien de status van de knop in de hoofdthread moet worden gewijzigd).
Binnenkant van de addOperation
blokkeren, moet u het volgende toevoegen schakelaar
verklaring om te controleren wat de autorisatiestatus eigenlijk is:
schakelstatus case .authorized: dictationButton.isEnabled = true promptLabel.text = "Tik op de knop om het dictaat te starten ..." default: dictationButton.isEnabled = false promptLabel.text = "Dictation not authorized ..."
We schakelen de retourwaarde van de authorizationStatus ()
functie. Als de actie is geautoriseerd (staat
is .gemachtigde
), is de dictaatknop ingeschakeld en Tik op de knop om het dictaat te starten ... is weergegeven. Anders is de dicteerknop uitgeschakeld en Dicteren niet toegestaan ... is weergegeven.
Vervolgens moeten we een gebruikersinterface ontwerpen om twee dingen te kunnen doen: het dictaat starten of stoppen en de geïnterpreteerde tekst weergeven. Ga hiervoor naar Main.storyboard het dossier.
Dit zijn de drie interfacebouwer-elementen die u nodig hebt om door te gaan met deze zelfstudie:
UILabel
UITextView
UIButton
Omdat plaatsing niet centraal staat in deze app, zal ik niet precies aangeven waar en hoe alles te plaatsen, dus volg gewoon dit eenvoudige draadframe bij het plaatsen van uw gebruikersinterface-elementen:
Als een referentiepunt, hier is hoe mijn storyboard eruit ziet op dit punt:
Nogmaals, het is goed als je lay-out er anders uitziet, maar zorg er gewoon voor dat je dezelfde drie basiselementen in het draadframe hebt. Plak de volgende coderegels naar de bovenkant van uw ViewController ()
klasse:
@IBOutlet var promptLabel: UILabel! @IBOutlet var transcribedTextView: UITextView! @IBOutlet var dictationButton: UIButton!
Op weg naar de bodem van de ViewController ()
klasse, voeg gewoon de volgende functie toe die moet worden geactiveerd wanneer op de dictaatknop wordt getikt:
@IBAction func dictationButtonTapped () // Uw code komt hier
Het laatste wat je nog moet doen, is het openen van de Assistent redacteur en verbind de verbindingen van de interfacebouwer met uw Main.storyboard het dossier. De stippen die ernaast verschijnen, moeten nu gevuld worden weergegeven en u kunt nu al deze elementen openen als variabelen en methoden, respectievelijk.
Nu zijn we eindelijk klaar om spraakherkenning te starten. De eerste stap is om de juiste variabelen en constanten te maken die we tijdens het hele proces zullen gebruiken. Onder de uitbreidingen van uw interfacebuilder, voegt u de volgende coderegels toe:
laat audioEngine = AVAudioEngine () laat speechRecognizer = SFSpeechRecognizer (locale: Locale (identifier: "en-US"))! var request: SFSpeechAudioBufferRecognitionRequest? var-taak: SFSpeechRecognitionTask?
Hier is een beschrijving van wat de variabelen en constanten doen:
Audioengine
is een instantie van de AVAudioEngine ()
klasse. Deze klasse is, in eenvoudige bewoordingen, een reeks audioknooppunten. Audioknooppunten worden gebruikt om verschillende dingen met audio te doen, zoals het genereren en verwerken ervan.speechRecognizer
is een instantie van de SFSpeechRecognizer ()
klasse. Deze klasse herkent niets anders dan de opgegeven taal, in dit geval Amerikaans Engels.verzoek
is een optionele variabele van het type SFSpeechAudioBufferRecognitionRequest
, en het wordt momenteel geïnitialiseerd om nul
. Later in deze tutorial zullen we er één van maken en de waarde ervan bepalen wanneer we deze moeten gebruiken. Dit wordt gebruikt om de invoergegevens van de microfoon van het apparaat te herkennen.taak
is een andere optionele variabele, deze tijd van het type SFSpeechRecognition
. Later zullen we deze variabele gebruiken om de voortgang van onze spraakherkenning te volgen.Nadat u de variabelen hebt toegevoegd, hebt u alles wat u nodig hebt om rechtstreeks in het spraakherkenningsproces te duiken.
Nu gaan we de belangrijkste methode gebruiken voor ons algoritme voor spraakherkenning. Onder de viewDidLoad ()
methode, verklaar de volgende functie:
func startDictation () // Uw code komt hier
Omdat we de huidige status van de .nl niet kennen taak
, we moeten de huidige taak annuleren en vervolgens moeten we deze opnieuw instellen nul
(in het geval dat het nog niet is). Dit kan gedaan worden door de volgende twee regels code aan uw methode toe te voegen:
taak? .cancel () task = nil
Super goed! Nu weten we dat er nog geen taak actief is. Dit is een belangrijke stap wanneer u variabelen gebruikt die buiten het bereik van de methode zijn gedeclareerd. Een ding om op te merken is dat we optionele chaining gebruiken om te bellen annuleren()
op taak
. Dit is een beknopte manier van schrijven die we alleen maar willen bellen annuleren()
als taak
is niet nul.
Nu moeten we de variabelen initialiseren die we eerder in deze zelfstudie hebben gemaakt. Om verder te gaan, voegt u deze regels code toe aan uw startDictation ()
methode uit de vorige stap:
request = SFSpeechAudioBufferRecognitionRequest () laat audioSession = AVAudioSession.sharedInstance () laat inputNode = audioEngine.inputNode guard let request = request else return request.shouldReportPartialResults = true try? audioSession.setCategory (AVAudioSessionCategoryRecord) probeer het? audioSession.setMode (AVAudioSessionModeMeasurement) proberen? audioSession.setActive (true, with: .notifyOthersOnDeactivation)
Laten we het afbreken. Herinner de verzoek
variabele die we eerder hebben gemaakt? De eerste coderegel initialiseert die variabele met een instantie van de SFSpeechAudioBufferRecognitionRequest
klasse.
Vervolgens wijzen we de instantie van de gedeelde audiosessie toe aan een constante opgeroepen audioSession
. De audiosessie gedraagt zich als een tussenpersoon tussen de app en het apparaat zelf (en de audiocomponenten).
Daarna zetten we het ingangsknooppunt op een singleton genaamd inputNode
. Om te beginnen met opnemen, maken we later een tik
op dit knooppunt.
Vervolgens gebruiken we een bewaker om het uit te pakken verzoek
variabele die we eerder hebben geïnitialiseerd. Dit is eenvoudig om te voorkomen dat u dit later in de toepassing moet uitpakken. Dan zullen we de weergave van onvolledige resultaten mogelijk maken. Dit werkt op dezelfde manier als dicteren op de iPhone - als je ooit dictaat hebt gebruikt, weet je dat het systeem alles opneemt wat het denkt, en vervolgens, met behulp van contextaanwijzingen, dingen aanpast indien nodig.
Ten slotte proberen de laatste drie coderegels verschillende kenmerken van de audiosessie in te stellen. Deze bewerkingen kunnen fouten veroorzaken, dus ze moeten worden gemarkeerd met de proberen?
trefwoord. Om tijd te besparen, negeren we eventuele fouten die optreden.
Nu hebben we de meeste variabelen geïnitialiseerd die voorheen in de nulstatus waren. Een laatste variabele om te initialiseren is de taak
variabel. Dat doen we in de volgende stap.
Voor de initialisatie van deze variabele is een afhandelingsafhandeling vereist. Plak de volgende code onder aan uw startDictation ()
methode:
task = speechRecognizer.recognitionTask (met: request, resultHandler: (resultaat, fout) in guard laat resultaat = 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))
Eerst maken we een recognitionTask
met de verzoek
als een parameter. De tweede parameter is een afsluiting die de resultaathandler definieert. De resultaat
parameter is een instantie van SFSpeechRecognitionResult
. Binnen deze voltooiingshandler moeten we de resultaatvariabele opnieuw uitpakken.
Vervolgens stellen we de tekst van onze tekstweergave in als de beste transcriptie die het algoritme kan bieden. Dit is niet noodzakelijk perfect, maar het algoritme denkt dat het het beste past bij wat het hoorde.
Ten slotte, binnen dit als
verklaring, controleren we eerst of er een fout is of dat het resultaat is voltooid. Als een van deze waar is, stoppen de audiomachine en andere gerelateerde processen en verwijderen we de tik
. Maak je geen zorgen, je zult in de volgende stap meer te weten komen over tikken!
Eindelijk, het moment waarop je hebt gewacht! We kunnen eindelijk de motor starten die we al zo lang hebben gecreëerd. We doen dat door een "tik" te installeren. Voeg de onderstaande code toe onder je taak
initialisatie:
laat recordingFormat = inputNode.outputFormat (forBus: 0) inputNode.installTap (onBus: 0, bufferSize: 1024, format: recordingFormat) (buffer, wanneer) in self.request? .append (buffer)
In deze code stellen we het uitvoerformaat van het ingangsknooppunt in op een constante aanroep recordingFormat
. Dit wordt in de volgende stap gebruikt om een audio te installeren tik
op het ingangsknooppunt om audio op te nemen en te bewaken. In de voltooiingshandler voegen we de buffer
in een PCM-indeling aan het einde van het herkenningsverzoek. Om de motor te starten, voegt u gewoon de volgende twee regels code toe:
audioEngine.prepare () proberen? audioEngine.start ()
Dit bereidt zich eenvoudig voor en probeert vervolgens de audiomotor te starten. Nu moeten we deze methode via onze knop noemen, dus laten we dat doen in de volgende stap.
We willen niet dat de gebruiker spraakherkenning kan activeren tenzij deze beschikbaar is voor gebruik, anders kan de app vastlopen. We kunnen dit doen via een gedelegeerde methode, dus voeg de volgende paar regels code onder de startDictation ()
methode verklaring:
func speechRecognizer (_ speechRecognizer: SFSpeechRecognizer, availabilityDidChange beschikbaar: Bool) indien beschikbaar dictationButton.isEnabled = true else dictationButton.isEnabled = false
Dit wordt gebeld wanneer spraakherkenning beschikbaar komt nadat deze niet beschikbaar of niet beschikbaar is nadat deze beschikbaar was. Binnenin gebruiken we gewoon een if-instructie om de knop in of uit te schakelen op basis van de beschikbaarheidsstatus.
Wanneer de knop is uitgeschakeld, ziet de gebruiker niets, maar reageert de knop niet op tikken. Dit is een soort vangnet om te voorkomen dat de gebruiker te snel op de knop drukt.
Het laatste wat u hoeft te doen, is reageren wanneer de gebruiker op de knop tikt. Hier kunnen we ook wijzigen wat de knop zegt en de gebruiker vertellen wat hij moet doen. Om je geheugen op te frissen, hier is de @IBAction
we hebben eerder gemaakt:
@IBAction func dictationButtonTapped () // Uw code komt hier
Voeg binnen deze functie de volgende if-instructie toe:
if audioEngine.isRunning dictationButton.setTitle ("Start Recording", for: .normal) promptLabel.text = "Tik op de knop om te dicteren ..." request? .endAudio () audioEngine.stop () else dictationButton.setTitle (" Stop Recording ", for: .normal) promptLabel.text =" Ga je gang Ik luister ... "startDictation ()
Als de audiomachine al draait, willen we de spraakherkenning stoppen en de juiste prompt voor de gebruiker weergeven. Als het niet actief is, moeten we de herkennings- en weergaveopties voor de gebruiker starten om het dictaat te stoppen.
Dat is het! U hebt een app gemaakt die uw stem kan herkennen en transcriberen. Dit kan voor verschillende toepassingen worden gebruikt om gebruikers die op andere manieren geen interactie met uw apps kunnen hebben, te helpen. Als je deze tutorial leuk vond, bekijk dan zeker de andere in deze serie!
En terwijl je hier bent, bekijk enkele van onze andere berichten over Swift- en iOS-app-ontwikkeling!