SwiftUIとSpeech Frameworkで動画の文字起こしアプリを作ってみる
音声認識に興味が出たので、Apple製のSpeech FrameworkとSwiftUIを使って簡易的なMacアプリ作ってみたので得られた知見をご紹介します。
完成品
ニュース動画なのでアナウンサーの声だけでノイズがないからか、かなりの精度
開発環境
- SwiftUI
- Speech Framework
- Swift5.1
- macOS 10.15.2(Catalina)
- Xcode 11.3.1
MacでSpeech FrameworkとSwiftUI使えるのはCatalina以降なので最新版にアップデートしましょう
SwiftUIベースのMacアプリ作成
新規プロジェクトでSwiftUIを選択
create new project
からmacOSのAppを選択し、User Interface
の項目をSwiftUI
にします
初期状態で作成されるContentView.swift
にレイアウト定義と音声認識の処理をつらつら書いていきます。
SwiftUIといえど、Viewに処理を書くのはあまり良くありませんが、今回は簡易的なアプリなので、 全部Viewに処理を書いてしまいます
import SwiftUI
import Speech
struct ContentView: View {
@State var recognizedText: String?
@State var message: String = ""
private let speechRecognizer = SFSpeechRecognizer(locale: Locale(identifier: "ja-JP"))
var body: some View {
VStack(alignment: .trailing) {
Text(recognizedText ?? "")
.font(.body)
.frame(width: 480, height: 320, alignment: .top)
.border(Color.gray)
.padding()
HStack {
Text(message)
Button("Choose file") {
SFSpeechRecognizer.requestAuthorization { (status) in
guard status == .authorized else {
print("音声入力が認可されていません")
return
}
// NSOpenPanelはMain Threadからのみアクセス可
DispatchQueue.main.async {
let panel = NSOpenPanel()
let result = panel.runModal()
guard result == .OK, let url = panel.url else {
print("ファイル読み込みに失敗")
return
}
let speechRequest = SFSpeechURLRecognitionRequest(url: url)
self.message = "音声認識中..."
self.recognizedText = ""
_ = self.speechRecognizer?.recognitionTask(with: speechRequest, resultHandler: { (speechResult, error) in
guard let speechResult = speechResult else {
return
}
if speechResult.isFinal {
self.message = "音声認識が完了しました"
print("Speech in the file is \(speechResult.bestTranscription.formattedString)")
} else {
let text = speechResult.bestTranscription.formattedString
self.recognizedText = text
}
})
}
}
}
}.padding()
}
}
}
コード解説
@State
SwiftUIのホットリロード機能の一番簡単な@State
を用いて、UI更新処理を書かないようにしています
NSOpenPanel
Macのファイルダイアログをプログラムから呼ぶのはNSOpenPanel
というクラス使うらしいです。初めてしりました。Viewファイルに書いてあるから大丈夫かと思いきや明示的にMainスレッド指定しないと実行時エラーになってしまうので注意
SFSpeechRecognizer
今回のアプリの肝のクラスですね
日本語の文字起こしを想定しているので ローカル情報をja-JP
にしたインスタンスを保持。
ユーザ認可をリクエストしたのち、ファイルダイアログから取得できたファイルのURLでSFSpeechURLRecognitionRequest
のインスタンスを作って、認識タスクをコールバックと同じく登録して完了です。
コールバックで返却されるSFSpeechRecognitionResult
に認識結果が返ってくるので、それを画面に表示してあげるだけで完了です。
.bestTranscription.formattedString
というプロパティにいわゆる文字起こし結果が入ってきますが、他にも声の抑揚や、話す早さなどが返ってくるのが面白いところなので、興味ある方は色々デバッグして見てみると良いかもしれません。
注意点
plistに音声入力の説明を定義忘れずに
NSSpeechRecognitionUsageDescription
に音声入力を許可するダイアログ時の文言をセットを忘れずに
最近めっきりプライバシーに厳しいAppleフレームワーク。他のフレームワーク同様、音声入力もユーザ認可が必要なのであしからず。
音声認識できる時間の上限が1分
オンラインを介した音声認識のみ、上限が設けられています。
これはそもそもiOS等々のキーボードからの音声入力が1分という上限があるかららしい。(バッテリーや通信量に配慮する為)
1分ごとに区切ってタスクを捌いていけば、長時間動画の完全文字起こしもいけそう?
iOS13から端末上のみで音声認識できるようになり、そちらなら上限はないようだが、対応言語が絞られる(日本語非対応)上に継続的に改善されるオンラインとは違い、精度が良くないとのこと。この辺はトレードオフですね。
まとめ
SwiftUIとSpeech Framework凄すぎ
音声認識の知識ほぼ皆無な私でも簡単なアプリ作れちゃうくらいシンプルなインターフェイスと使いやすいフレームワークな上に精度もかなりでビックリしました。
Macアプリは殆ど作ったことない私でもこれ、ググったりするだけで1時間くらいで作成できました(むしろこのQiita書くほうが時間かかってる。。。)
参考にした記事
Author And Source
この問題について(SwiftUIとSpeech Frameworkで動画の文字起こしアプリを作ってみる), 我々は、より多くの情報をここで見つけました https://qiita.com/rymshm/items/5ea968acb686c53133c7著者帰属:元の著者の情報は、元のURLに含まれています。著作権は原作者に属する。
Content is automatically searched and collected through network algorithms . If there is a violation . Please contact us . We will adjust (correct author information ,or delete content ) as soon as possible .