字幕&翻訳機能を作って世界中の配信を聞いてみよう REALITY Advent Calendar 2023
Merry Christmas Eve! REALITY Advent Calendar 2023 の24日目担当の @chuymaster です!iOSアプリ開発およびローカライズ周りの改善を担当をしています。
最近、私はインドネシア語を独学で学んでいて、たまにインドネシア地域の配信を聞きに行きますが、全然何を言っているかが分からなくてモヤモヤな気持ちです。
ということで、配信者さんが話していることを字幕に表示して、翻訳できたら分かるようになるのでは?と思って、開発合宿で字幕機能を作ってみました!
背景
ご存知かもしれませんが、REALITYは日本以外のユーザーが約8割を占めていて、非常に国際色が豊かなサービスです。アプリの地域・言語設定を変えれば、様々な地域のユーザーと交流することができます。もし字幕・翻訳機能があれば、各地域のユーザーがより交流しやすくなって、コミュニティーが活発になると考えます。
ちなみにREALITYはローカライズにも力を入れています。よかったら下記の発表や記事も見てみてください!
機能イメージ
今回実装する機能は、視聴者の画面に「字幕」メニューを追加して、配信者の音声をリアルタイムでテキストに変換して、さらに任意の言語でリアルタイム翻訳する機能です。
作ったもの
できたものがこちらです!
もちろん、日本語だけではなく、他の言語でも字幕起こしができ、リアルタイムで翻訳できるので、他の国の配信者の内容も分かるようになります!
使っている技術
リアルタイム音声認識技術と翻訳技術は様々ありますが、今回は下記を利用しました。
音声認識技術:iOSの機能「SFSpeechRecognizer」
翻訳については外部APIを利用して、音声認識したテキストを翻訳してもらっているだけのため、詳細を割愛します。主にiOSのSFSpeechRecognizerについて解説します。
SFSpeechRecognizerの実装コード
SFSpeechRecognizerはiOSの音声認識機能で、iOS12から使えて、iOS13からはネットワーク通信せず、完全に端末内で音声認識が可能になりました。
音声認識の実装は、Appleのサンプルコードを参考すると簡単にデモが作れると思いますのでチェックしてみてください!
今回の実装ではSFSpeechRecognizerを処理するクラスはこのように作りました。
class LiveCaptionUseCase: NSObject {
private let disposeBag = DisposeBag()
private var speechRecognizer: SFSpeechRecognizer?
private var recognitionRequest: SFSpeechAudioBufferRecognitionRequest?
init(audioBuffer: Signal<AVAudioPCMBuffer>) {
super.init()
// 認識したい言語をLocaleに設定。サンプルでは日本語で固定
speechRecognizer = SFSpeechRecognizer(locale: Locale(identifier: "ja-JP"))
recognitionRequest = makeSpeechRecognitionRequest()
audioBuffer
.emit { [weak self] buffer in
// リアルタイム音声を音声認識リクエストに流す
self?.recognitionRequest?.append(buffer)
}.disposed(by: disposeBag)
}
}
SFSpeechAudioBufferRecognitionRequest はリアルタイム音声の音声認識に使用します。REALITYでは既に AVAudioPCMBuffer で音声をリアルタイム再生しているので、RxSwiftで音声データが流れるイベントを取って音声認識リクエストに流すだけで実装が完了します。
音声認識リクエストの設定がこちらです。
private func makeSpeechRecognitionRequest() -> SFSpeechAudioBufferRecognitionRequest? {
let recognitionRequest = SFSpeechAudioBufferRecognitionRequest()
// デバイス内で音声認識を行う。
recognitionRequest.requiresOnDeviceRecognition = true
// 最後まで話すのを待たずに、発話の度にすぐに認識結果をもらう
recognitionRequest.shouldReportPartialResults = true
if #available(iOS 16, *) {
// 「、」「。」等の記号をテキストに入れる
recognitionRequest.addsPunctuation = true
}
speechRecognizer?.recognitionTask(with: recognitionRequest) {result, error in
if let result {
// 音声認識のテキストをUIに表示
print(result.bestTranscription.formattedString)
} else if let error {
if (error as NSError).code == 1110 {
// 音声認識できないエラーの対応
} else if (error as NSError).code == 301 {
// キャンセルの対応
} else {
// 不明なエラーの対応
}
}
}
return recognitionRequest
各種オプションの意味はそのままですが、解説すべきなのはrequiresOnDeviceRecognition オプションです。
true の場合
精度が落ちる代わり、完全にデバイス内で音声認識を行う。
通信量の削減・プライバシーの強化が期待できる。
話を止めると、自動で文章を区切ってくれる。
日本語と英語はかなり正確に認識できるが、インドネシア語やタイ語では全然認識ができなかった。(iOS 17.2で確認)
false の場合
Appleサーバーに音声認識をしてもらうので、精度が上がる。
インドネシア語やタイ語も認識が可能。
自動で文章を区切ることなく、音声認識リクエストを開始したら、明示的にキャンセルさせないとテキストがずっと長く続いてしまう。
上記の説明のように、どちらを指定しても問題があり、原因が不明なので、本実装をする際はきちんと調査する必要があります。
今回の機能のポイント
今回作った機能は、2022年の開発合宿でIKEPさんが挑戦したものから発展した機能です。
一番の違いは、音声認識を完全にデバイス内で行うことが可能なので、ランニングコストゼロで機能を提供することができます。翻訳についても、MLKit Translationのような、デバイス内でできるフレームワークがあるので、機会があれば調査して組み込みたいと思います。
おまけ:字幕機能が今すぐ使える方法
今日からでも字幕機能を体験したい方は、iOS/Androidが標準で提供する字幕起こし機能を使うことができます。
iOSは iOS 17以上で、英語のみ対応しています。
AndroidはPixelシリーズで日本語も対応しています。
OSが提供する機能も素晴らしいですが、REALITYアプリに組み込み、手間なく使えてこそ、真価が発揮されると思います。いつか形にして機能を提供し、世界各地のREALITYユーザーがより繋がりやすいようにしていきたいです!
明日のアドベントカレンダーは
今年最後のアドベントカレンダーを飾るのは、kuyamaさんの「新アバターアイテム:エフェクト」です!お楽しみに!