普段、自分の業務ではあまり必要になったことないんですが、先日業界の飲み会で割とUT記録の書き起こしして、そして苦労してるんだなと感じたので、ちょうどいま別件でWatsonを活用する仕事に関わってるのでAPIの勉強がてらツールをプロトタイピングしてみました。
UTの動画ファイルから音声を分離し、Wasonにアップ、返ってきたJSON形式のテキストを見やすいタブ区切りテキストに変換し、拙作のフリーソフト動画眼 (タイムスタンプ付きテキストをクリックすると動画の頭出しをしてくれる)に元の動画といっしょに食わせるところまで成功。
その様子がこちら(文字が読めるよう全画面表示でご覧いただくことをオススメします)。
VIDEO
精度としては感覚的に6割以下ってところですかね。モデレーターの「よろしくお願いします」みたいなはっきりかつ頻出なフレーズはちゃんと拾えるけど、被験者の思考発話は途中で途切れたり文章として成立しない場合も多いので、AI補完が入って語尾が勝手にかわったりしがち。単語も全然違ったりしてます。アスキングのコメントは少しマシですかね。まぁ、それでも、
動画からあるシーンを探し出して見返したいというスポッティング作業の効率向上
ゼロから手で起こすより、これを直していった方が早いのでは仮説(対応してくれる業者いるのかしら)
とか場面を限定すれば実用性はありそう。
費用感ですが、本ツールを無償で公開したとして、WasonのSpeech To Text API の利用料が(辞書登録など音声モデルのカスタマイズをした場合で)$0.03/分なので、60分のセッションを丸起こしさせたとして200円くらい?音声ファイルの長さで計算されるのか、変換にかかった時間なのか不明あやふやですが、実際変換はほぼ実時間くらいかかるのでどちらでもそう変わらないかと。結果がいまいちで、そのタスクや業界固有の用語を辞書に追加したりして何度かやり直しかけたりしてもまぁそんなにスゴい値段にはならないかと。
以下ざっくりステップ毎に解説。
0. WatsonのID取得
先日無償化が発表されましたがSpeech-to-Textは対象に含まれず。執筆時点で30日無料体験もあります。
1. 音声ファイルの用意
ICレコーダーで録ったならそのまま使える。ビデオカメラやスマホカメラの場合、音声だけ抽出してwavやmp3、ogg、WebM、flacなどにする必要があります。後述のCurlを使うアップロード方法(Sessionless)だと100MBまでしか一度に送れないので、mp3やflacのような圧縮率の高い形式にするのがヨサゲ。可逆の方が精度は出るだろうからflacがいいかも知れない(そういえばFLACで直接録音できるICレコーダーってないのかな?)。まぁコーデックやビットレートでどれくらい差が出るかはちゃんと検証できてないです。
今回は1万円ちょっとするPegasysのTMPGEnc Video Mastering Works 6を使用しましたが、カット編集が不要ならフリーでいくらでもあると思います。>音声分離
2.音声ファイルをWasonにアップロード
専用ツールを開発しない場合、黒い画面で使うCurlというテキストブラウザが使える(ブラウザからでもできると思うけど一括自動かという意味で)。CurlはmacOSなら標準搭載。Windowsだと自分でダウンロード&インストールが必要。そしてコマンドラインオプションとして、アップするファイル名、モデルと言語指定、出力ファイル名、タイムスタンプをつけるオプション、話者識別記号をつけるオプションだと、100文字以上の呪文になる(コード例1)ので、今回ツール1 として、Windows向けフォームアプリを作成(画面写真1)。ちょうやっつけGUIですが、音声ファイルをドラッグ&ドロップし、IBM CloudのID&PWを設定したら送信ボタンを押すだけで、結果がテキストファイルに保存されます。認識にはほぼ実時間かかるので、複数ファイルをまとめて逐次処理できるようにしています。
# curl -X POST -u <ユーザ名>:<パスワード> --header "Content-Type:audio/wav --data-binary @<音声ファイル名>.wav "https://stream.watsonplatform.net/speech-to-text/api/v1/recognize?timestamps=true&model=ja-JP_BroadbandModel&speaker_labels=true&word_confidence=false" -o <出力ファイル名>.txt
コード例1. Curlによる送信例
↑これが↓こう。
画面写真1. 作成したプロトアプリ
CurlのフロントエンドUIを作っただけなので、Sessionlessなままで100MB制限が残る。もうちょっと真面目に作ってSessionあり(常時通信)で実装しなおせばそこら辺はとっぱらえるし、その気になればリアルタイムでテキストが落ちてくるような形もできるはず。
また辞書登録は未実装。WatonのAPIとしては、例えばサンプルでは「安藤」が「&」に認識いされちゃってるけど、そういうのを狙った表記に寄せられる。また「アイトリプルイー」とか出てきたら「IEEE」と書け、いったことにも使える(とマニュアルに書いてある)。
あと作ってからlibcurlの存在に気付く。これを使う用にすれば別途Curlをインストールすることなしに配布できるのかな?ちょっとライセンス周りを勉強しておきます。C#用のラッパーも見つけました 。
3. JSON形式からの変換
Watsonからの戻りデータはWebエンジニアさんにはお馴染みのJSONなので普通に眺めるには辛い。
こんな感じ。
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
{
"results" : [
{
"alternatives" : [
{
"timestamps" : [
[
"よろしく" ,
17.8 ,
18.16
] ,
[
"お願い" ,
18.52 ,
18.78
] ,
[
"します" ,
18.78 ,
19.06
]
] ,
"confidence" : 0.753 ,
"transcript" : "よろしく お願い します "
}
] ,
"final" : true
} ,
{
"from" : 17.8 ,
"to" : 18.16 ,
"speaker" : 0 ,
"confidence" : 0.554 ,
"final" : false
} ,
{
"from" : 18.52 ,
"to" : 18.78 ,
"speaker" : 0 ,
"confidence" : 0.297 ,
"final" : false
}
] ,
"result_index" : 1 ,
"speaker_labels" : [
{
"from" : 18.78 ,
"to" : 19.06 ,
"speaker" : 0 ,
"confidence" : 0.297 ,
"final" : false
} ,
]
}
単純にtranscriptを抜き出せば良さそうですが、これにはタイムスタンプがついてきません。ので手前の「よろしく」についてる17.8秒という情報を使います。またそのタイムスタンプで誰がしゃべってるかをspeaker_labelsオブジェクトから探してきて、speakerプロパティを抽出する必要がありました。ちなみにcondidenceは信頼度、つまりWatsonの自信度合いで0〜1の値がつきます。
で、これを自動でタブ区切りテキストに変換するため、ツール2 としてC#でコマンドラインツールを作成。Visual Studio for Macで作ってmacOSで動いてますが、まぁ前後ツールの関係で実質はWindowsで使うことになりますかね?ただ自分でWatsonに投げられて、Excelで読めればいいやって向きにはMac版のニーズもあるかも知れません。VS for Macが吐いた.exeファイルをVS無しで単体で実行可能にする方法をまだ調べてない…(それよかツール1をMacに対応させた方が早いかもしれません。Xamarin.Formとか使えば両方で動くものにできるんじゃないかと)
ツール2はコマンドラインツールですが、使い方は変換するファイル名をオプションでつけるだけ。ただ後も先も.txtファイルなのでファイル名をどうしようか思案中。今は末尾に.txtをついかしてるので、hoge.txt.txtみたいになってしまう。動画眼で使うなら動画ファイル名と同名拡張子違いが一番都合がいいので、アップローダーで保存するファイル名を、hoge.watson.txtになるようにして、こっちで.watsonを抜く、とかがいいかな。
・タイムスタンプ
Watsonに投げる時に timestamps=true オプションをつけると、上記例の通り単語というか音節ごとにタイムスタンプがついてきます。残念ながら文章単位ではない。そこでひとまとまりの文章の中の最初の固まりの先頭タイムスタンプをとってきて文章とセットにする、という処理をしている。
・話者認識
同様に speaker_labels=trueオプションをつけると話者情報(speaker_label)がついてきます。デモ動画の中では「」の前にある0とか2が話者コードです。最初の登場人物から順に0からふられてくぽい。この動画では二人しか出てこないはずなんですが、なにかが一瞬1と誤認され、以降0さん(被験者)と2さん(モデレーター)になってしまいました。これも文章単位ではなく音節単位でしかも末尾にまとめて付加されるので処理が面倒でした。また全体としては1つの文章として認識してるのに、話者コードが途中で入れ替わることもあります。片方の発話を遮るようにもう一人がしゃべりだしたりするとそうなりがち。結局transcroptionプロパティを捨てて、alternative1つずつを拾ってつないでいきつつ、話者コードを調べて切り替わった時点で手動で文章も切り離すという処理にし、実装にえらい苦労しました…
数字を名前に置換する機能とかあるといいんでしょうけど、認識してみないと誰が何番になるかわからないので、このJSON変換ツールでというより動画眼なり後段階のツールの仕事にするのがいいかなと思っています。
4. 動画眼(既存ツール)
動画眼 はタイムコードとメモがタブ区切りペアになったテキストファイルと、動画または音声ファイルをセットで読み込んで、メモ(発話内容や行動)をダブルクリックすると、そのシーンが頭出し再生される、もしくは再生しながらメモを書き込むとタイムスタンプ付きで記録してくれる、というUT見返し用の拙作フリーソフトウェアで、こちら で配布しています。
今回3.のツール2の出力はこれと互換性があるので、元になった動画/音声ファイルとツール2が出力したタブ区切りテキストを読み込ませることで、サンプル動画のようなことが可能になる。なお、青いフォーカス行が移動してるのは手動で操作してるからです。動画の進行にあわせて自動で進んでくわけではありませんのであしからず。
あとこうなってくると検索機能が欲しいよなってことで、初リリースから十余年を経てついに実装しました(何故か考えたことすらなかったw)。近日リリースします。
まとめ
とまぁ書き起こしてみると大変そうだけれど、一度セットアップしてしまえばそれなりの手軽さでここまでできるよっていう技術デモです。驚愕するほどの認識精度ではないですが、実際にセッションを見ていたモデレーターや見学者が、概要思い出したり、特定のシーンを探す手助けくらいにはなるんじゃないかと。また書き起こしをする際のドラフトに使ったらゼロから手で起こすよりは楽になるんじゃないかとか。精度は録音状態にも大きく左右されますね。今回は10年以上前にとったもので撮影機材は定かではないですが、DVだったような気がします。取り込んだ動画の音声はPCMでしたが途中不可逆圧縮を経たか不明。いずれにせよアップロード段階でMP3にしちゃいました。WAVのままで短い区間で試したサンプルはもうちょいマシだったような気もしますが定量的には比べてないです。別件で携わっている教室のディスカッション起こしは別グループの声とかノイズが多いので話者毎に口元マイクを使って別トラックでとるということをして、精度を追求していますが、UTの実務現場ではなかなか現実的ではないかなと。なるべく高音質に録って、そのままWatsonにいれるのが良さそう。その意味でツール2をセッションレスからセッション通信に再実装して100MB以上のアップができるようにしておきたいところです。
ツール1、2はもう少し整備してから公開しようと思っています。コードが汚いと叩かれそうだけどソースごとGitHubにあげましょうかね。誰かが活用&改善してくれることを願って。まずは多少のセットアップはいとわないので試してくれるクローズドβテスターさんがいたらお声がけください。
謝辞
本記事のトライアルにあたっって、羽山さん(@storywriter )の記事 を大変参考にさせていただきました。この場を借りてお礼申し上げます。また今度是非Watsonトークしましょう!