SFSpeechRecognizer は音声フレームワークに属しており、iOS 10 で初登場し、iOS 13 でメジャーアップデートされました。iOS 13 ではオフライン音声認識と音声分析をサポートしています。WWDC2019 では AI 分野における進歩が実証され、その中でも iOS 13 デバイスに組み込まれた音声認識は比較的優れた機能です。
1. どのようなアップグレードが行われましたか?
モバイル端末のオフライン音声認識モデルにより、ユーザー漏洩のリスクが軽減され、ユーザーのプライバシーが向上します。新しい API は、音声分析メトリクスを使用した音声品質や音声パターンの追跡など、多くの新機能をサポートしています。
同時に、デバイス上のオフライン モデルは音声認識を無期限にサポートできます。これは、1 分間しか認識されなかった以前のバージョンの iOS 10 と比較すると、大幅な改善です。もちろんデメリットもあり、クラウド型のようにオンラインで学習することができません。これにより、デバイスの精度がいくらか低下します。
iOS 13 SFSpeechRecognizer もはるかに賢く、音声内の句読点を認識できます。たとえば、ピリオドが認識され、カンマ、ダッシュなどの他の記号も認識されます。ただし、現時点では認識されたテキストに句読点を追加できないという欠点があります。ただし、iOS 16 ではこれが解決され、それに応じて精度が向上しました。多くの有料音声認識フレームワークを置き換えることができるようになりました。
2. 成果を上げる
最初にエフェクトを確認してください。スクリーンショットは完全にオフラインの機内モードで撮影されたものであることに注意してください。
今回はマイクを介して音声認識を行いますが、SFSpeechRecognizer は音声ファイル認識もサポートしていますので、興味のある方はご自身で調べてみてください。
3. 動作原理
上の図はリアルタイム音声認識の内部実装です。音声認識は次の 4 つに依存します。
- AVオーディオエンジン
- SFS音声認識装置
- SF認識タスク
- SFSpeechAudioBufferRecognitionRequest
次に、これらがどのように機能するかを見てみましょう。
初心者向けに、まずユーザーのプライバシー権限に関連するコンテンツを紹介します。
プライバシーに関する指示の追加
ここでは、以下に示すように、マイクと音声認識に関するプライバシーに関する指示を追加する必要があります。
要求权限
SFSpeechRecognizer.requestAuthorization { authStatus in
switch authStatus { case .authorized: case .restricted: case .notDetermined: case .denied: } }
var speechRecognizer = SFSpeechRecognizer(ロケール: Locale(識別子: “zh-CN”)) の初期化
4. 実装
4.1 AVAudioEngine の設定
AVAudioEngine は、マイクから音声信号を収集し、その音声信号を SFSpeechAudioBufferRecognitionRequest に渡す役割を果たします。
let audioEngine = AVAudioEngine()
let audioSession = AVAudioSession.sharedInstance()
try audioSession.setCategory(.record, mode: .measurement, options: .duckOthers)
try audioSession.setActive(true, options: .notifyOthersOnDeactivation)
let inputNode = audioEngine.inputNode
// 在安装 tap 之前先移除上一个 否则可能报
// "*** Terminating app due to uncaught exception 'com.apple.coreaudio.avfaudio', reason: 'required condition is false: nullptr == Tap()"之类的错误
inputNode.removeTap(onBus: 0)
let recordingFormat = inputNode.outputFormat(forBus: 0)
// bufferSize:传入缓冲区的请求大小
// 创建一个“tap”来记录/监视/观察节点的输出
// bus:连接tap的节点输出总线
inputNode.installTap(onBus: 0, bufferSize: 1024, format: recordingFormat) {
(buffer: AVAudioPCMBuffer, when: AVAudioTime) in
self.recognitionRequest?.append(buffer)
}
audioEngine.prepare()
try audioEngine.start()
上記のコードは、ホストにタップをインストールし、出力バッファ サイズを設定します。このバッファは、発話または録音時にオーディオ信号をキャッシュするために使用されます。
バッファ サイズがいっぱいになると、SFSpeechAudioBufferRecognitionRequest に送信されます。
次に、SFSpeechAudioBufferRecognitionRequest が SFSpeechRecognizer と SFSpeechRecognitionTask を使用して音声をテキストに書き起こす方法を見てみましょう。
4.2 デバイスの音声認識を有効にする
recognitionRequest.requiresOnDeviceRecognition = true
音声認識に Apple Cloud を使用するには false に設定します。RequiredOnDeviceRecognition は iOS 13、macOS Catalina 以降のデバイスでのみ利用できることに注意してください。iOS の iPhone6s 以降のデバイスでサポートされている Apple の A9 以降のプロセッサが必要です。
4.3 SFSpeechRecognitionTask の作成
SFSpeechRecognitionTask は、SFSpeechAudioBufferRecognitionRequest と SFSpeechRecognizer の実行に使用されます。block と delegate の 2 つのメソッドがあります。次の例では、結果をコールバックする block メソッドを使用し、結果を通じてさまざまな音声属性にアクセスします。bestTranscription は、最も高い信頼度でオプションを識別します
recognitionTask = speechRecognizer?.recognitionTask(with: recognitionRequest) {
result, error in
// 处理识别结果
if let result = result {
DispatchQueue.main.async {
let transcribedString = result.bestTranscription.formattedString
self.transcribedText.text = (transcribedString)
}
}
// 异常处理
if error != nil {
self.audioEngine.stop()
inputNode.removeTap(onBus: 0)
self.recognitionRequest = nil
self.recognitionTask = nil
}
}
4.4 SFVoiceAnalytics
SFVoiceAnalytics は、音声結果のピッチ、フリッカー、ジッターなどの特性を追跡する一連の音声メトリクスを含む、新しく導入されたクラスです。これらには、トランスクリプションのセグメント属性からアクセスできます。
for segment in result.bestTranscription.segments {
guard let voiceAnalytics = segment.voiceAnalytics else {
continue }
let pitch = voiceAnalytics.pitch
let voicing = voiceAnalytics.voicing.acousticFeatureValuePerFrame
let jitter = voiceAnalytics.jitter.acousticFeatureValuePerFrame
let shimmer = voiceAnalytics.shimmer.acousticFeatureValuePerFrame
}
4.5 音声認識
上で 4 つのコンポーネントについて説明しましたが、全体としてどのように機能するかを以下のコードで見てみましょう。
private let audioEngine = AVAudioEngine()
private var recognitionRequest: SFSpeechAudioBufferRecognitionRequest?
private var speechRecognizer = SFSpeechRecognizer(locale: Locale(identifier: "zh-CN"))
private var recognitionTask: SFSpeechRecognitionTask?
func startRecording() throws {
recognitionTask?.cancel()
self.recognitionTask = nil
let audioSession = AVAudioSession.sharedInstance()
try audioSession.setCategory(.record, mode: .measurement, options: .duckOthers)
try audioSession.setActive(true, options: .notifyOthersOnDeactivation)
let inputNode = audioEngine.inputNode
inputNode.removeTap(onBus: 0)
let recordingFormat = inputNode.outputFormat(forBus: 0)
inputNode.installTap(onBus: 0, bufferSize: 1024, format: recordingFormat) {
(buffer: AVAudioPCMBuffer, when: AVAudioTime) in
self.recognitionRequest?.append(buffer)
}
audioEngine.prepare()
try audioEngine.start()
recognitionRequest = SFSpeechAudioBufferRecognitionRequest()
guard let recognitionRequest = recognitionRequest else {
fatalError("Unable to create a SFSpeechAudioBufferRecognitionRequest object") }
// 分部返回结果,每次识别完成就会回调部分结果
recognitionRequest.shouldReportPartialResults = true
if #available(iOS 16, *) {
// iOS 16 已经支持自动添加标点符号,不需要再喊标点符号了
recognitionRequest.addsPunctuation = true
}
if #available(iOS 13, *) {
if speechRecognizer?.supportsOnDeviceRecognition ?? false{
recognitionRequest.requiresOnDeviceRecognition = true
}
}
recognitionTask = speechRecognizer?.recognitionTask(with: recognitionRequest) {
result, error in
if let result = result {
DispatchQueue.main.async {
// 获取置信度最高的 transcription,并格式化为字符串
let transcribedString = result.bestTranscription.formattedString
self.transcribedText.text = (transcribedString)
}
}
if error != nil {
self.audioEngine.stop()
inputNode.removeTap(onBus: 0)
self.recognitionRequest = nil
self.recognitionTask = nil
}
}
}
上記のコードは比較的長いので、上記のコードについて説明しましょう。
-
[記録認識の開始] を押すときは、まず以前の認識タスクをキャンセルしてください。
-
SFSpeechRecognizer と SFSpeechAudioBufferRecognitionRequest を使用して、認識タスク SFSpeechRecognitionTask を作成します。
-
shouldReportPartialResults を true に設定すると、認識中に中間結果にアクセスできるようになります。
-
result.bestTranscription は、最も高い信頼度で識別された文字起こしを返し、formattedString プロパティは文字起こしテキストを提供します。
-
speechRate、averagePauseDuration、セグメントなどの他のプロパティにもアクセスできます。
5. まとめ
これは基本的に、マイクを介して音声をテキストに認識するプロセス全体です。使用される SFSpeechAudioBufferRecognitionRequest は、SFSpeechRecognitionRequest のサブクラスです。また、別のサブクラス SFSpeechURLRecognitionRequest もあり、ローカル録音ファイル パスを通じて認識できます。興味がある場合は、次のことができます。もう一度見てください。
実際のアプリケーション シナリオでは、サードパーティの SDK を使用して AudioBuffer オーディオ情報を提供することが可能であり、この例では AVAudioEngine を使用して AudioBuffer を提供しています。実際、recognitionRequest を通じて自分でバッファを追加することもできます。試すことができます。