Hungarian (Magyar) translation by Andras Czegledi (you can also view the original English article)

Bevezetés
A Siri az iOS egyik fő funkciójává vált mióta 2011-ben bemutatták. Az iOS 10-zel az Apple új funkciókat vezet be, amivel a fejlesztők hozzáférhetnek Sirihez. Két új framework vált elérhetővé: a Speech és a SiriKit.
Ebben a cikkben a Speech framework-kel fogunk foglalkozni, amivel könnyed fordíthatunk hangfájlokat szöveggé. Meg fogjuk tanulni, hogyan építsünk egy működő appot ami a beszédfelismerő API használatával ellenőrzi egy repülőjárat helyzetét.
Hogyha többet szeretnél tudni a SiriKit-ről, olvasd át a Create SiriKit Extensions in iOS 10 bejegyzésemet. Ha pedig az iOS 10 fejlesztők számára elérhető új funkciói érdekelnek, olvasd el Markus Mühlberger kurzusát, itt az Envato Tuts+-on.
- iOS SDKSiriKit kiegészítők készítése iOS 10-ben (Create SiriKit Extensions in iOS 10)Patrick Balestra
- iOSAz iOS 10 újdonságai (What's New in iOS 10)Markus Mühlberger
Kezelés
A beszédfelismerés alatt az élőbeszéd vagy az előre felvett hangfájl szöveggé alakítását értjük. Mióta Siri bemutatkozott az iOS 5-ben, a billentyűzeten megjelent egy mikrofon gomb, amivel a felhasználók diktálhatnak a telefonnak. Ez a funkció bármelyik UIKit szöveges beviteli mezőben alkalmazható, és nem szükséges extra kódot írni egy standard szövegmező kódján kívül. Nagyon gyorsan és könnyen használható, de van néhány limitációja:
- A billentyűzet folyamatosan a képernyőn van diktálás közben.
- A nyelvet nem változtathatja meg az app.
- Az app nem értesülhet róla, hogy a diktálás mikor kezdődik és mikor ér véget.

Annak érdekében hogy a fejlesztők még jobban testreszabbható és jobban használható applikációkat fejleszthessenek a Siri technológiáját felhasználva, az Apple megalkotta a Speech framework-öt. Ezzel minden eszköz ami iOS 10-et futtat képes az audio szöveggé konvertálására, több mint 50 nyelven és dialektusban.
Ez az új API sokkal több dologra képes, mert így nem csak szövegleiratot készít, hanem alternatívákat is felajánl, ha nem érti pontosan hogy a felhasználó mit mondott. A fejlesztő kontrollálhatja hogy mikor legyen a diktálásnak vége, a keresési találatokat beszéd közben is meg lehet mutatni, illetve a beszédfelismerő rendszer automatikusan adaptálódik a felhasználó preferenciáihoz (nyelv, szókincs, nevek, stb.).
Egy érdekes funkció az előre felvett szöveg feldolgozása. Ha például egy üzenetküldő alkalmazást készítesz, akkor ezzel leiratot készíthetsz az audioüzenetekről.
Beállítás
Először is meg kell kérdezned a felhasználót, hogy hozzájárul-e ahhoz, hogy a hangüzeneteit továbbítsuk az Apple-nek analízisre.
Az eszköztől és a felismerendő nyelvtől függően az iOS eldöntheti, hogy magán az eszközön fordítja a hangot szövegre, illetve - ha a lokális beszédfelismerés nem elérhető - továbbítja azt az Apple szervereire.
Ezért szükséges általában aktív internetkapcsolat a beszédelismeréshez. Mindjárt megmutatom, hogy hogyan ellenőrizheted a szolgáltatás elérhetőségét.
A beszédfelismerés három lépésből áll:
- Magyarázás: írd le a felhasználónak hogy miért akarsz hozzáférni a hangfájljaihoz.
- Engedélyezés: expliciten kérj engedélyt a hangfájlokhoz való hozzáférésre.
- Kérelem: tölts be egy előre felvett audiofájlt a lemezről a
SFSpeechURLRecognitionRequest
paranccsal, vagy streamelj audiót aSFSpeechAudioBufferRecognitionRequest
paranccsal, majd dolgozd fel a szöveget.
Hogyha többet szeretnél tudni a Speech framework-ről, nézd meg a 2016-os WWDC 509-es előadását, illetve olvasd el a hivatalos dokumentációt.
Példa
Most pedig megmutatom hogyan készíts egy igazi applikációt ami a beszédfelismerő API-t használja. Egy egyszerű repülőjárat-követő appot fogunk készíteni, amiben a felhasználó csak kimondja a járat számát, az app pedig megmutatja a repülő állapotát. Így igaz, egy apró asszisztenst fogunk készíteni, mint a Siri, ami bármelyik repülőjárat adatait le tudja kérdezni!
Ennek a bejegyzétsnek a GitHub repo-jába feltöltöttem a projekt vázát, amiben egy egy egyszerű UI lesz a segítségünkre a tutorial során. Töltsd le és nyisd meg a projektet Xcode 8.2-ben vagy annak újabb verziójában. Mivel az UI már megvan, nekünk már csak a beszédfelismerő API-ra fókuszálnunk.
Nézzük meg a projektben található class-okat. Az UIViewController+Style.swift
tartalmazza az UI frissítéséért felelős kódot. A járatok adatbázisa a FlightsDataSource.swift
-ban egy táblázatban van tárolva.
Ha lefuttatod a projektet, így kell kinéznie.

Miután a felhasználó megnyomja a mikrofon gombot, elindítjuk a beszédfelismerést hogy lementsük a járatszámot. Tehát ha a felhasználó kimondja hogy "LX40", megmutatjuk neki hogy melyik kapuhoz kell mennie és mi a járat státusza. Ehhez meghívunk egy függvényt ami kikeresi a járatot az adatbázisból és megmutatja a státuszt.
Először azt vizsgáljuk meg, hogyan tudunk előre felvett audiófájlt feldolgozni. Később megtanuljuk az előbeszéd felismerését is, ami sokkal érdekesebb lesz.
Először is álltsuk be a projektet. Nyisd meg az Info.plist
fájlt és adj hozzá egy új sort, aminek a szövegét a felhasználó akkor fogja látni, amikor hozzáférést kérünk a hangfájlokhoz. Az újonnan hozzáadott sor kék kiemeléssel látható az alábbi képen.

Ha ez megvan, nyisd meg a ViewController.swift
fájlt. Ne foglalkozz a kóddal ami már alapból benne van a class-ban; ez csak az UI frissítését végzi el nekünk.
Minden új framework esetén az első lépés hogy beimportáljuk azt a fájl elején:
import Speech
Az engedélykérő ablak feldobásához add hozzá az alábbi kódot a viewDidLoad(animated:)
metódushoz:
switch SFSpeechRecognizer.authorizationStatus() { case .notDetermined: askSpeechPermission() case .authorized: self.status = .ready case .denied, .restricted: self.status = .unavailable }
A status
változó végzi el azt az UI változtatást ami a felhasználót figyelmezteti, hogy a beszédfelismerés nem lesz elérhető ha valami hiba történik. Minden alkalommal amikor meg akarjuk változtatni az UI-t, új értéket adunk a változónak.
Ha az app még nem kért engedélyt a felhasználótól, az engedélyezés státusza notDetermined
lesz, és meghívjuk az askSpeechPermission
metódust hogy engedélyt kérjünk, ahogy az a következő lépésben látható majd.
Ha egy bizonyos funkció nem elérhető, mindig graceful fail-t kell alkalmazni. Ezen kívül nagyon fontos, hogy mindig kommunikáld a felhasználó felé ha rögzíted a hangját. Soha ne próbáld meg felismertetni a hangját anélkül, hogy ezt kijeleznéd az UI-t, vagy anélkül hogy a felhasználó nem tud róla.
Íme az engedélykérő függvény implementációja.
func askSpeechPermission() { SFSpeechRecognizer.requestAuthorization { status in OperationQueue.main.addOperation { switch status { case .authorized: self.status = .ready default: self.status = .unavailable } } } }
A requestAuthorization
metódus meghívásával megjelenítjük a beszédfelismeréshez szükséges engedélykérő ablakot, amit az Info.plist
-ben definiáltunk. Ezután átváltunk a fő thread-re ha a lezárás egy másik thread-ről hívódott meg - mivel csak a fő thread-ről akarjuk frissíteni az UI-t. A status
-hoz új értéket rendelünk, ami frissíti a mikrofon gombot, ezzel is jelezve a felhasználó felé hogy a beszédfelismerés elérhető-e.
Beszédfelismerés előre felvett audiofájlból
Mielőtt megírjuk az előre felvett audió beszédfelismerés kódját, meg kell találnunk az audiófájl URL-jét. A project navigatorban keresd meg az LX40.m4a
fájlt. Az iPhone-omon lévő Voice Memos app-al felvettem, ahogy kimondom azt hogy "LX40". Ezzel könnyedén ellenőrizhetjük hogy jó leiratot kapunk-e az audiófájlból.
Tároljuk el az audiófájl URL-jét egy property-ben:
var preRecordedAudioURL: URL = { return Bundle.main.url(forResource: "LX40", withExtension: "m4a")! }()
Most végre megismerkedhetünk a Speech framework egyszerűségével és hatékonyságával. Íme a kód ami az egész beszédfelismerést végzi:
func recognizeFile(url: URL) { guard let recognizer = SFSpeechRecognizer(), recognizer.isAvailable else { return } let request = SFSpeechURLRecognitionRequest(url: url) recognizer.recognitionTask(with: request) { result, error in guard let recognizer = SFSpeechRecognizer(), recognizer.isAvailable else { return self.status = .unavailable } if let result = result { self.flightTextView.text = result.bestTranscription.formattedString if result.isFinal { self.searchFlight(number: result.bestTranscription.formattedString) } } else if let error = error { print(error) } } }
Nézzük mit is csinál ez a metódus:
- Inicializálja az
SFSpeechRecognizer
instance-et és a guard utasítással leellenőrzi, hogy működik-e a beszédfelismerés. Ha nem működik, akkor a status visszatérési értékétunavailable
-re állítjuk. (Az alapértelmezett inicializátor az alapértelmezett felhasználói nyelvet (locale) használja, de ha eltérő nyelvet szeretnél beállítani, használhatod azSFSpeechRecognizer(locale:)
inicializátort is). - Ha a beszédfelismerés elérhető, létrehozza az
SFSpeechURLRecognitionRequest
instance-t az előre felvett audiófájl URL-jének átadásával. - Elindítja a beszédfelismerést a
recognitionTask(with:)
metódus meghívásával az előbb létrehozott request-ből.
A lezárás (closure) többször is meg fog hívódni két paraméterrel: egy eredmény- és egy hibaobjektummal.
A recognizer
lejátssza a fájlt és megpróbálja inkrementálisan felismerni a szöveget. Ezért hívódik meg a lezárás többször. Minden alkalommal amikor felismer egy betűt, vagy szót, vagy amikor javításokat végez, a lezárás meghívódik frissített objektumokkal.
A result
objektum isFinal
tulajdonsága true-ra állítódik amikor az audiófájl analizálása befejeződött. Ebben az esetben elindítunk egy keresést az adatbázisunkban, hogy megtaláljuk a járatot a felismert járatszám alapján. A searchFlight
függvény fogja megjeleníteni az eredményt.
Az utolsó dolog amit el kell végeznünk a recognizeFile(url:)
függvény meghívása a mikrofon gomb megnyomásakor:
@IBAction func microphonePressed(_ sender: Any) { recognizeFile(url: preRecordedAudioURL) }
Futtasd le az appot egy iOS 10-es eszközön, nyomd meg a mikrofon gombot, és látni fogod az eredményt. Az "LX40" hangfájlt inkrementálisan felismeri az eszköz, és megjeleníti a járat állapotát!
Tipp: A járatszám egy UITextView-ban jelenik meg. Ahogyan azt bizonyára észrevetted, ha bekapcsolod a járatszám detektort az UITextView-ban, akkor rá is nyomhatsz, és a járat jelenlegi állapota fog megjelenni!
A teljes példakód eddig a pontig megtekinthető a GitHub-on a pre-recorded-audio branch-ben.
Élőbeszéd felismerés
Lássuk hogyan implementálhatjuk az élőbeszéd felismerését. Ez egy kicsit bonyolultabb lesz annál mint amit eddig csináltunk. Töltsd le ismét a projekt vázát és kövesd a tutorialt.
Szükségünk van egy új kulcsra az Info.plist
fájlban, hogy elmagyarázzuk a felhasználónak miért kell hozzáférnünk a mikrofonhoz. adj hozzá egy új sort az Info.plist
-hez ahogy a képen látható.

Nem szükséges manuálisan engedélyt kérnünk a felhasználótól, mert az iOS megteszi azt helyettünk amint megpróbálunk hozzáférni bármilyen mikrofonhoz kötődő API-hoz.
Újra felhasználhatjuk ugyanazt a kódot amit az előző fejezetben használtunk az engedélykéréshez (ne felejtsd el az import Speech
parancsot). A viewDidLoad(animated:)
metódust ugyanúgy implementáljuk, mint korábban:
switch SFSpeechRecognizer.authorizationStatus() { case .notDetermined: askSpeechPermission() case .authorized: self.status = .ready case .denied, .restricted: self.status = .unavailable }
A felhasználótól való hozzáférés kérése is megegyezik.
func askSpeechPermission() { SFSpeechRecognizer.requestAuthorization { status in OperationQueue.main.addOperation { switch status { case .authorized: self.status = .ready default: self.status = .unavailable } } } }
A startRecording
implementációja egy kicsit eltérő lesz. Először is adjunk hozzá néhány instance változót, amik később az audio session-öknél és a beszédfelismerésnél hasznosak lesznek.
let audioEngine = AVAudioEngine() let speechRecognizer: SFSpeechRecognizer? = SFSpeechRecognizer() let request = SFSpeechAudioBufferRecognitionRequest() var recognitionTask: SFSpeechRecognitionTask?
Nézzük egyesével aváltozókat:
- Az
AVAudioEngine
dolgozza fel az audio stream-et. Létrehozunk egy audio node-ot és hozzáadjuk ehhez az engine-hez, így értesülni fogunk róla ha a mikrofon audiojeleket vesz. - Az
SFSpeechRecognizer
ugyanaz az osztály amivel a tutorial előző részében is találkozhattunk, ez végzi a beszéd felismerését. Mivel az inicializátor elbukhat és nil értékkel is visszatérhet, opcionálisnak deklaráljuk, hogy elkerüljük a futás közbeni összeomlást. - Az
SFSpeechAudioBufferRecognitionRequest
egy buffer ami az előbeszédet ismeri fel. Mivel most nincs egy teljes audiofájlunk mint az előbb volt, szükségünk van egy bufferra, amibe a beszédet tölthetjük, miközben a felhasznál beszél. - Az
SFSpeechRecognitionTask
menedzseli a beszédfelismerési task-okat, ezzel állítható meg illetve törölhető a folyamat.
Miuttán minden szükséges változót deklaráltunk, implementáljuk a startRecording
-ot.
func startRecording() { // Setup audio engine and speech recognizer guard let node = audioEngine.inputNode else { return } let recordingFormat = node.outputFormat(forBus: 0) node.installTap(onBus: 0, bufferSize: 1024, format: recordingFormat) { buffer, _ in self.request.append(buffer) } // Prepare and start recording audioEngine.prepare() do { try audioEngine.start() self.status = .recognizing } catch { return print(error) } // Analyze the speech recognitionTask = speechRecognizer?.recognitionTask(with: request, resultHandler: { result, error in if let result = result { self.flightTextView.text = result.bestTranscription.formattedString self.searchFlight(number: result.bestTranscription.formattedString) } else if let error = error { print(error) } }) }
Ez az általunk létrehozott funkció kódja. Elmagyarázom lépésenként:
- Először megkapjuk az
audioEngine
inputNode
-ját. Egy eszköznek több audióinputja lehet, itt az elsőt választjuk ki. - Beállítjuk az input node-ban hogy az audio stream-et akarjuk monitorozni. Az általunk megadott blokk minden 1024 bájtnyi audio stream után meghívódik. Rögtön hozzáadjuk az audio buffert a
request
-hez, hogy azonnal megkezdhesse a beszédfelismerést. - Felkészítjük az audio engine-t a felvétel elkezdéséhez. Ha a felvétel elkezdődik, akkor a status-t
.recognizing
-ra állítjuk a gomb ikonját pedig megváltoztatjuk hogy a felhasználót értesítsük arról, hogy felvesszük a hangját. - Rendeljük hozzá a
speechRecognizer.recognitionTask(with:resultHandler:)
-ből visszakapott onbjektumot arecognitionTask
változóhoz. Ha a beszédfelismerés sikeres volt, akkor kikeressük a járatot az adatbázisból és frissítjük az UI-t.
A felvétel megállításához csak le kell állítanunk az audio engine-t, kitöröljük az input node-ot és megállítjuk a beszédfelismerés task-ot.
func cancelRecording() { audioEngine.stop() if let node = audioEngine.inputNode { node.removeTap(onBus: 0) } recognitionTask?.cancel() }
Mostmár csak a felvétel elindítása és megállítása van hátra. Módosítsuk a microphonePressed
metódust az alábbiak szerint:
@IBAction func microphonePressed() { switch status { case .ready: startRecording() status = .recognizing case .recognizing: cancelRecording() status = .ready default: break } }
A status
változó értéke alapján elindítjuk vagy megállítjuk a beszédfelismerést.
Build-eld és futtasd az app-ot a végeredmény megtekintéséhez. Próbáld lebetűzni bármelyik járatot angol kiejtés szerint és meg fog jelenni annak állapota a kijelzőn.
A példakód elérhető GitHub-on a live-audio branch-ben.
Legjobb gyakorlatok
A beszédfelismerés egy nagyon hasznos API amit az Apple az iOS 10-et célzó fejlesztők számára készített. A használata ingyenes, de jó ha tudod hogy nem használható végtelen alkalommal. Minden egyes beszédfelismerés task körülbelül egy percre van limitálva, ezen kívül az app-odat az Apple szerverei is lelassíthatja, ha túl sok számítási erőforrást használ fel. Mindezek miatt nagy hálózati forgalmat generál és az akkumulátort is nagy mértékben meríti.
Győződj meg róla hogy a felhasználók tisztában vannak a beszédfelismerés működésével, és mindig tájékoztasd a felhasználót arról ha a hangját rögzíted.
Összegzés
Ebben a tutorial-ban megtanultuk hogyan használjuk az iOS 10 gyors, pontos és rugalmasbeszédfelismerését. Ezzel a felhasználók többféle módon kezelhetik az app-odat, így azok számára is jól használható lesz, akik számára az érintőkijelző kezelése problémát okoz.
Ha többet szeretnél tudni arról hogy hogyan integrálhatod Siri-t az applikációdban, vagy hogyha az iOS 10 fejlesztői újításaira vagy kiváncsi, tekitsd meg Markus Mühlberger kurzusát.
Tekintsd meg a többi ingyenes bejegyzésünket is az iOS 10 funkcióiról.
- iOSFrissítsd az applikációdat iOS 10-re (Upgrade Your App to iOS 10)Bart Jacobs
- iOS SDKiOS 10: Egyedi notifikációs interface-ek készítése (iOS 10: Creating Custom Notification Interfaces)Davis Allie
- iOS 10Rezgő visszajelzés az iOS 10-ben (Haptic Feedback in iOS 10)Patrick Balestra
- iOS SDKSiriKit kiegészítők készítése iOS 10-ben (Create SiriKit Extensions in iOS 10)Patrick Balestra
Envato Tuts+ tutorials are translated into other languages by our community members—you can be involved too!
Translate this post