音声ファイルから台本を自動生成する with Whisper

# 1.背景
会社でMTGの録画などを見直す際に「あの話題の付近を見返したいんだけど探すの面倒くさいな...」ってなることないですか？
そんなときにMTGの台詞とタイムスタンプを抽出出来たら、不要な時間を削減出来て会社に貢献できるんじゃないかと思ってこの記事を書きました。

...というのは建前で、音声作品とかを再度聴くときに「あれ？これってどんなシチュだったっけ？」っていうのを防止するのに台本を自動生成出来たら良いなと思って調べ始めました。

# 2.Whisperとは
OpenAIがリリースした音声認識モデルで以下のような特徴があります。
- 音声認識の精度がとても高い
- 日本語を含んだ99言語に対応している
- 5種類の大きさのモデルが用意されているので、必要な精度や解析速度に合わせた選択ができる

# 3.実装
今回は米津玄師さんの「lemon」の音声ファイルから歌詞を自動生成したいと思います。
実装は環境構築がほぼ必要ないGoogleColaboratoryで行いました。
また、実行の前に"ランタイム"→"ランタイムのタイプを変更"→"ハードウェアアクセラレータ"→"GPU"を選択することによって実行時間を大幅に減らすことができます。

## 3-1.インストール
```
!pip install git+https://github.com/openai/whisper.git
!pip install datetime
```
まず、Whisperをインストールします。
後で時間表示に使うので、ついでにdatetimeもインストールしておきます。

## 3-2.音声認識モデルの作成
```
import whisper
import datetime

# モデルのモード選択
model = whisper.load_model("small")
```
次に、音声認識モデルを作成します。
モデル作成の際に認識精度のモードを選択する必要があるので、「tiny」「base」「small」「medium」「large」の5つの中から選びます。今回は、smallを選択しました。右に行くほど認識の精度が上がりますが、その分解析に時間がかかります。
これ以外にもモードはありますが、日本語対応しているものはこの5つです。

## 3-3.音声ファイルの解析
```
# 音声ファイルの解析
result = model.transcribe("/content/hogehoge.mp3", verbose=False, language='ja')
```
ここで本命の音声ファイルの解析を行います。
GoogleColaboratoryを使っている場合はファイル直下に読み込ませたい音声ファイル配置し、ファイル名を"hogehoge"部に入れてあげると読み込むことができます。

## 3-4.解析結果の表示
```
# 歌詞の表示
for seg in result["segments"]:
  start = datetime.timedelta(seconds=int(seg["start"]))
  end = datetime.timedelta(seconds=int(seg["end"]))
  print(f'{start}-{end} {seg["text"]}')
```

いよいよ待ちに待った歌詞の出力です！
ついでに、曲のどの部分の歌詞なのかが分かるようにタイムスタンプの出力も追加しました。
以下はsmallモデルで歌詞を出力したものの一部です。

```
0:00:00-0:00:08 夢ならばどれほどよかったでしょう
0:00:08-0:00:13 未だにあなたの鼓動を夢に見る
0:00:13-0:00:19 忘れたものの鳥に帰るように
0:00:19-0:00:25 古い歌思い出の誇りをは
0:00:26-0:00:32 戻らない幸せがあることを
...
```

<details>
<summary>歌詞全文</summary>
0:00:00-0:00:08 夢ならばどれほどよかったでしょう<br>
0:00:08-0:00:13 未だにあなたの鼓動を夢に見る<br>
0:00:13-0:00:19 忘れたものの鳥に帰るように<br>
0:00:19-0:00:25 古い歌思い出の誇りをは<br>
0:00:26-0:00:32 戻らない幸せがあることを<br>
0:00:32-0:00:38 最後にあなたが教えてくれた<br>
0:00:38-0:00:43 言えずに隠してた暗い過去も<br>
0:00:43-0:00:49 あなたがいなきゃ永遠に暗いまま<br>
0:00:49-0:00:55 きっともうこれ以上傷つくことなど<br>
0:00:55-0:01:00 あの日はしないとわかっている<br>
0:01:00-0:01:03 あの日の悲しみさえ<br>
0:01:03-0:01:05 あの日の苦しみさえ<br>
0:01:05-0:01:11 そのすべてを愛してたあなたと共に<br>
0:01:11-0:01:17 胸に残り離れない苦いレモンの匂い<br>
0:01:17-0:01:22 雨が降り止むまでは帰れない<br>
0:01:22-0:01:28 今でもあなたは私の光<br>
0:01:39-0:01:44 暗闇であなたの背をなすをった<br>
0:01:44-0:01:49 その輪郭を千倍に溺れている<br>
0:01:49-0:01:55 受け止めきれないものと出会う度<br>
0:01:55-0:02:01 溢れて止まないのは涙だけ<br>
0:02:01-0:02:07 何をしていたの?何を見ていたの?<br>
0:02:07-0:02:11 私の知らないよこれが俺<br>
0:02:11-0:02:17 どこかであなたが今私と同じような<br>
0:02:17-0:02:22 涙にくれ寂しさの中身いるなら<br>
0:02:22-0:02:28 私のことなどどうか忘れてください<br>
0:02:28-0:02:34 そんなこと心から願うほどに<br>
0:02:34-0:02:40 今でもあなたは私の怒り<br>
0:02:42-0:02:53 自分が思うより顔してたあなたに<br>
0:02:53-0:02:59 あれから思うより<br>
0:02:59-0:03:04 雪が出来ない<br>
0:03:04-0:03:10 あんなにそばにいたのに<br>
0:03:10-0:03:15 まるで嘘みたい<br>
0:03:15-0:03:21 時も忘れられない<br>
0:03:21-0:03:27 それだけが確か<br>
0:03:28-0:03:34 あの日の悲しみさえ<br>
0:03:34-0:03:37 あの日の苦しみさえ<br>
0:03:37-0:03:42 そのつらでも愛してたあなたと共に<br>
0:03:42-0:03:48 胸に残り離れない未来は物にも<br>
0:03:48-0:03:54 雨が降り止むまでは帰れない<br>
0:03:54-0:03:59 切り分けた果実の方のように<br>
0:03:59-0:04:06 今でもあなたは私の怒り<br>
</details>

ちょくちょく間違いはあるものの、かなりの精度で認識できていることが分かります。また、3行目の「取りに帰る」が「鳥に帰る」のようなミスも音的には合っているため、音声認識の面から見た場合はかなりの精度を誇っているといえそうです。
なお、smallを選択した際の解析時間は4分の動画に対して40秒程度でした。かなり短時間で解析が完了でき精度も高めなので、リアルタイムで解析する必要があるようなものはこのモデルか、より早く解析できる「tiny」や「base」を使えば良いと思います。

<details>
<summary>歌詞全文(large)</summary>
0:00:00-0:00:05 夢ならばどれほどよかったでしょう<br>
0:00:05-0:00:11 未だにあなたのことを夢にみる<br>
0:00:11-0:00:17 忘れたものを取りに帰るように<br>
0:00:17-0:00:23 古びた思い出の埃を払う<br>
0:00:23-0:00:32 戻らない幸せがあることを<br>
0:00:32-0:00:38 最後にあなたが教えてくれた<br>
0:00:38-0:00:43 言えずに隠してた暗い過去も<br>
0:00:43-0:00:49 あなたがいなきゃ永遠に暗いまま<br>
0:00:49-0:00:55 きっともうこれ以上傷つくことなど<br>
0:00:55-0:01:00 ありはしないとわかっている<br>
0:01:00-0:01:05 あの日の悲しみさえ あの日の苦しみさえ<br>
0:01:05-0:01:11 そのすべてを愛してたあなたとともに<br>
0:01:11-0:01:17 胸に残り離れない苦いレモンの匂い<br>
0:01:17-0:01:22 雨が降り止むまでは帰れない<br>
0:01:22-0:01:28 今でもあなたは私の光<br>
0:01:39-0:01:44 暗闇であなたの背をなぞった<br>
0:01:44-0:01:49 その輪郭を鮮明に溺れている<br>
0:01:49-0:01:55 受け止めきれないものと出会うたび<br>
0:01:55-0:02:01 溢れてやまないのは涙だけ<br>
0:02:01-0:02:07 何をしていたの 何を見ていたの<br>
0:02:07-0:02:11 私の知らない横顔で<br>
0:02:11-0:02:17 どこかであなたが今 私と同じような<br>
0:02:17-0:02:22 涙につれ寂しさの中にいるなら<br>
0:02:22-0:02:28 私のことなどどうか忘れてください<br>
0:02:28-0:02:34 そんなことを心から願うほどに<br>
0:02:34-0:02:40 今でもあなたは私の光<br>
0:02:42-0:02:53 自分が思うように声をしていたあなたに<br>
0:02:53-0:03:04 あれから思うように息ができない<br>
0:03:04-0:03:10 あんなに傍にいたのに<br>
0:03:10-0:03:15 まるで嘘みたい<br>
0:03:15-0:03:21 とても忘れられない<br>
0:03:21-0:03:27 それだけが確か<br>
0:03:28-0:03:34 あの日の悲しみさえ あの日の苦しみさえ<br>
0:03:34-0:03:40 そのすべてを愛してたあなたと共に<br>
0:03:40-0:03:46 胸に残り離れない苦いレモンの匂い<br>
0:03:46-0:03:52 雨が降り止むまでは帰れない<br>
0:03:52-0:03:58 切り分けた果実の塊のように<br>
0:03:58-0:04:05 今でもあなたは私の光<br>
</details>

一方、largeで解析したところほとんどそのままの歌詞が生成出来ました！
解析時間は4分の音声ファイルに対して1分程度かかるので、smallほどの速度はありませんがある程度時間をかけても精度を出したい歌詞や台本の自動生成はこちらモデルを使ってみるのが良いかと思われます。

## 3-5.解析結果の保存
```
# 会話ログをtxtファイルに書き出し
f = open('台本.txt', 'x')
for seg in result["segments"]:
  start = datetime.timedelta(seconds=int(seg["start"]))
  end = datetime.timedelta(seconds=int(seg["end"]))
  f.write(f'{start}-{end} {seg["text"]}\n')
f.close()
```
このブロックを実行することで、3-4で出力した内容をtxtファイルに保存できます。
txtファイル名が重複するとエラーになるので、2回目以降の出力には注意が必要です。

# 4.まとめ
Whisperを使うことで音声から文字への変換が容易にできるようになりました！
活用方法としては以下のようなものが考えられます。
- MTGの議事録生成
- 歌詞の自動生成
- マイクとchatGPTの中継点として使用
- 翻訳した台詞にlive2Dで口パクつけて、自然な吹き替え動画に

特に3つ目は、chatGPTの回答を合成音声で読み上げさせることによってリアルタイムでの会話を可能にしている人もいたので夢が広がりますね！
今後は自分もWhisperとchatGPTと組み合わせて、何か面白いものが作りたいなと考えています。

# 5.参考サイト
https://dev.classmethod.jp/articles/whisper-trial-japanese/

https://medium.com/axinc/whisper-%E6%97%A5%E6%9C%AC%E8%AA%9E%E3%82%92%E5%90%AB%E3%82%8099%E8%A8%80%E8%AA%9E%E3%82%92%E8%AA%8D%E8%AD%98%E3%81%A7%E3%81%8D%E3%82%8B%E9%9F%B3%E5%A3%B0%E8%AA%8D%E8%AD%98%E3%83%A2%E3%83%87%E3%83%AB-b6e578f55c87#:~:text=Whisper%E3%81%AF2022%E5%B9%B410,%E3%82%92%E5%AE%9F%E7%8F%BE%E3%81%97%E3%81%A6%E3%81%84%E3%81%BE%E3%81%99%E3%80%82