0
0

Delete article

Deleted articles cannot be recovered.

Draft of this article would be also deleted.

Are you sure you want to delete this article?

Cloudflare Workers AI で Whisper Large V3 Turbo を使った日本語の文字起こしをする

Last updated at Posted at 2025-02-21

目的

Cloudflare Workers AI で Whisper Large V3 Turbo モデルが Beta になっています。

whisper-large-v3-turbowhisper-large-v3finetuned モデルで、多少の品質を犠牲にしながらも高速に動くモデルです。

Whisper large-v3-turbo is a finetuned version of a pruned Whisper large-v3. In other words, it's the exact same model, except that the number of decoding layers have reduced from 32 to 4. As a result, the model is way faster, at the expense of a minor quality degradation.

例えば、以下のような電話やミーティングの audio ファイルから WebVTT 形式の字幕ファイルを出力できます。

その後、場合によっては文字起こしデータから、要約や次のアクションの提示を事後処理として、さらに他の AI モデルを使って実行させるようなフローを実現できます。

参考: audio ファイルの抽出

ミーティング録画から audio ファイルを抽出するには以下の ffmpeg コマンドを使います。

ffmpeg -i ./cf-video.mp4 -vn ./cf-video.mp3

Workers AI デプロイ

以下の Workers コードを使用します。

以下のコマンドでデプロイできます。

export URL='https://github.com/kyouheicf/hello-whisper.git'
git clone $URL && cd $(basename $_ .git)
npx wrangler deploy 

使い方

以下のように URL の path パラメータとして audio ファイルの URL を記述すると、字幕データが返ってきます。

curl https://hello-whisper.xxx.workers.dev/https://example.com/cf-video.mp3 | jq
result.json
{
  "input": {
    "audio": []
  },
  "response": {
    "transcription_info": {
      "language": "ja",
      "language_probability": 1,
      "duration": 30.046625,
      "duration_after_vad": 30.046625
    },
    "segments": [
      {
        "start": 2.539999999999999,
        "end": 5.66,
        "text": "ミノシロ金3億円?そんな大金あるわけないだろ!",
        "temperature": 0,
        "avg_logprob": -0.2854399464649861,
        "compression_ratio": 1.62,
        "no_speech_prob": 0,
        "words": [
          {
            "start": 2.539999999999999,
            "end": 2.82,
            "word": "ミ"
          },
          {
            "start": 2.82,
            "end": 2.96,
            "word": "ノ"
          },
          ...
          {
            "start": 5.54,
            "end": 5.66,
            "word": "ろ!"
          }
        ],
        "word_count": 1
      },
      ...
      {
        "start": 25.62,
        "end": 29.46,
        "text": "サイバーセキュリティが、あなたの安心を守る。クラウドフレア。",
        "temperature": 0,
        "avg_logprob": -0.2854399464649861,
        "compression_ratio": 1.62,
        "no_speech_prob": 0,
        "words": [
          {
            "start": 25.62,
            "end": 25.9,
            "word": "サ"
          },
          ...
          {
            "start": 29.34,
            "end": 29.46,
            "word": "ア。"
          }
        ],
        "word_count": 1
      }
    ],
    "vtt": "WEBVTT\n\n00:02.540 --> 00:02.820\n\n\n00:02.820 --> 00:02.960\n\n\n00:02.960 --> 00:03.080\n\n\n00:03.080 --> 00:03.160\n\n\n00:03.160 --> 00:03.300\n\n\n00:03.300 --> 00:03.520\n3\n\n00:03.520 --> 00:03.740\n\n\n00:03.740 --> 00:03.880\n円?\n\n00:04.400 --> 00:04.680\nそんな\n\n00:04.680 --> 00:04.820\n\n\n00:04.820 --> 00:04.960\n\n\n00:04.960 --> 00:05.140\nある\n\n00:05.140 --> 00:05.220\n\n\n00:05.220 --> 00:05.320\n\n\n00:05.320 --> 00:05.400\nない\n\n00:05.400 --> 00:05.540\n\n\n00:05.540 --> 00:05.660\nろ!\n\n00:05.840 --> 00:06.000\nえっ?\n\n00:06.640 --> 00:06.880\n\n\n00:06.880 --> 00:07.060\nしか\n\n00:07.060 --> 00:07.300\nして。\n\n00:07.580 --> 00:07.860\n\n\n00:07.860 --> 00:07.940\n\n\n00:07.940 --> 00:08.040\n\n\n00:08.040 --> 00:08.120\n\n\n00:08.120 --> 00:08.280\n\n\n00:08.280 --> 00:08.480\n撃?\n\n00:08.880 --> 00:09.160\nまず\n\n00:09.160 --> 00:09.300\n\n\n00:09.300 --> 00:09.420\nな、\n\n00:09.500 --> 00:09.720\nそれ。\n\n00:10.140 --> 00:10.300\n\n\n00:10.300 --> 00:10.380\n\n\n00:10.380 --> 00:10.460\n\n\n00:10.460 --> 00:10.560\n\n\n00:10.560 --> 00:10.680\n\n\n00:10.680 --> 00:10.700\n\n\n00:10.700 --> 00:10.700\n\n\n00:10.700 --> 00:10.880\n\n\n00:10.880 --> 00:11.020\n\n\n00:11.020 --> 00:11.160\n\n\n00:11.160 --> 00:11.300\nれた。\n\n00:11.620 --> 00:11.900\n本当\n\n00:11.900 --> 00:12.080\nに?\n\n00:12.180 --> 00:12.340\n\n\n00:12.340 --> 00:12.420\n\n\n00:12.420 --> 00:12.520\n\n\n00:12.520 --> 00:12.640\nない?\n\n00:12.780 --> 00:12.940\n\n\n00:12.940 --> 00:13.040\n\n\n00:13.040 --> 00:13.120\nタ、\n\n00:13.360 --> 00:13.440\n\n\n00:13.440 --> 00:13.540\nック\n\n00:13.540 --> 00:13.680\n\n\n00:13.680 --> 00:13.740\n\n\n00:13.740 --> 00:13.860\nちゃ\n\n00:13.860 --> 00:13.960\nう。\n\n00:14.000 --> 00:14.140\n今、\n\n00:14.280 --> 00:14.300\n\n\n00:14.300 --> 00:14.420\n\n\n00:14.420 --> 00:14.480\n\n\n00:14.480 --> 00:14.580\nんだ\n\n00:14.580 --> 00:14.640\nよ、\n\n00:14.720 --> 00:14.780\nもう\n\n00:14.780 --> 00:14.960\n俺。\n\n00:16.740 --> 00:17.020\n大丈夫?\n\n00:17.680 --> 00:17.880\nん?\n\n00:19.400 --> 00:19.540\nん?\n\n00:20.700 --> 00:20.980\nああ、\n\n00:20.980 --> 00:21.260\n大丈夫。\n\n00:21.640 --> 00:21.840\n\n\n00:21.840 --> 00:21.900\n\n\n00:21.900 --> 00:22.000\n\n\n00:22.000 --> 00:22.060\n\n\n00:22.060 --> 00:22.200\n\n\n00:22.200 --> 00:22.240\n\n\n00:22.240 --> 00:22.280\n\n\n00:22.280 --> 00:22.420\n\n\n00:22.420 --> 00:22.660\n\n\n00:22.660 --> 00:22.800\nって\n\n00:22.800 --> 00:22.900\n\n\n00:22.900 --> 00:23.000\nれて\n\n00:23.000 --> 00:23.140\n\n\n00:23.140 --> 00:23.320\nから。\n\n00:23.500 --> 00:23.700\n\n\n00:23.700 --> 00:24.000\n\n\n00:24.000 --> 00:24.140\n\n\n00:24.140 --> 00:24.360\nよ!\n\n00:24.680 --> 00:24.880\n\n\n00:24.880 --> 00:24.980\n\n\n00:24.980 --> 00:25.080\n\n\n00:25.080 --> 00:25.180\n\n\n00:25.180 --> 00:25.260\nる?\n\n00:25.620 --> 00:25.900\n\n\n00:25.900 --> 00:25.960\n\n\n00:25.960 --> 00:26.040\n\n\n00:26.040 --> 00:26.120\n\n\n00:26.120 --> 00:26.220\n\n\n00:26.220 --> 00:26.280\n\n\n00:26.280 --> 00:26.360\n\n\n00:26.360 --> 00:26.380\n\n\n00:26.380 --> 00:26.480\n\n\n00:26.480 --> 00:26.500\n\n\n00:26.500 --> 00:26.680\nが、\n\n00:26.800 --> 00:27.180\n\n\n00:27.180 --> 00:27.300\nなた\n\n00:27.300 --> 00:27.440\n\n\n00:27.440 --> 00:27.580\n\n\n00:27.580 --> 00:27.800\n\n\n00:27.800 --> 00:27.920\n\n\n00:27.920 --> 00:28.120\n\n\n00:28.120 --> 00:28.300\nる。\n\n00:28.660 --> 00:28.940\n\n\n00:28.940 --> 00:28.980\n\n\n00:28.980 --> 00:29.060\n\n\n00:29.060 --> 00:29.120\n\n\n00:29.120 --> 00:29.260\n\n\n00:29.260 --> 00:29.340\n\n\n00:29.340 --> 00:29.460\nア。\n\n",
    "text": "ミノシロ金3億円?そんな大金あるわけないだろ! えっ?もしかして。 サイバー攻撃? まずいな、それ。 ガンサムウェア攻撃された。 本当に?やばくない? データ、ロックされちゃう。 今、来てるんだよ、もう俺。 大丈夫? ん? ん? ああ、大丈夫。クラウドフレアが守ってくれてるから。 正解だよ! 一緒に見る? サイバーセキュリティが、あなたの安心を守る。クラウドフレア。",
    "word_count": 15,
    "segment_vtt": "WEBVTT\n\n00:00:02.540 --> 00:00:05.660\nミノシロ金3億円?そんな大金あるわけないだろ!\n\n00:00:05.840 --> 00:00:07.300\nえっ?もしかして。\n\n00:00:07.580 --> 00:00:08.480\nサイバー攻撃?\n\n00:00:08.880 --> 00:00:09.720\nまずいな、それ。\n\n00:00:10.140 --> 00:00:11.300\nガンサムウェア攻撃された。\n\n00:00:11.620 --> 00:00:12.640\n本当に?やばくない?\n\n00:00:12.780 --> 00:00:13.960\nデータ、ロックされちゃう。\n\n00:00:14.000 --> 00:00:14.960\n今、来てるんだよ、もう俺。\n\n00:00:16.740 --> 00:00:17.020\n大丈夫?\n\n00:00:17.680 --> 00:00:17.880\nん?\n\n00:00:19.400 --> 00:00:19.540\nん?\n\n00:00:20.700 --> 00:00:23.320\nああ、大丈夫。クラウドフレアが守ってくれてるから。\n\n00:00:23.500 --> 00:00:24.360\n正解だよ!\n\n00:00:24.680 --> 00:00:25.260\n一緒に見る?\n\n00:00:25.620 --> 00:00:29.460\nサイバーセキュリティが、あなたの安心を守る。クラウドフレア。\n\n"
  }
}

WebVTT 形式の字幕ファイル保存

上記の vtt フィールドを使うと、日本語の場合、1文字ずつ分かれた出力となってしまい、字幕ファイルとしての使い勝手が悪いです。

そこで segments.text を変換した segment_vtt フィールドとして WebVTT 形式の字幕ファイルを出力するようにアレンジしています。

字幕ファイルとして保存する場合は、以下のコマンドを実行します。

curl https://hello-whisper.xxx.workers.dev/https://example.com/cf-video.mp3 \
| jq -r .response.segment_vtt > cf-video.vtt
cf-video.vtt
WEBVTT

00:00:02.540 --> 00:00:05.660
ミノシロ金3億円?そんな大金あるわけないだろ!

00:00:05.840 --> 00:00:07.300
えっ?もしかして。

00:00:07.580 --> 00:00:08.480
サイバー攻撃?

00:00:08.880 --> 00:00:09.720
まずいな、それ。

00:00:10.140 --> 00:00:11.300
ガンサムウェア攻撃された。

00:00:11.620 --> 00:00:12.640
本当に?やばくない?

00:00:12.780 --> 00:00:13.960
データ、ロックされちゃう。

00:00:14.000 --> 00:00:14.960
今、来てるんだよ、もう俺。

00:00:16.740 --> 00:00:17.020
大丈夫?

00:00:17.680 --> 00:00:17.880
ん?

00:00:19.400 --> 00:00:19.540
ん?

00:00:20.700 --> 00:00:23.320
ああ、大丈夫。クラウドフレアが守ってくれてるから。

00:00:23.500 --> 00:00:24.360
正解だよ!

00:00:24.680 --> 00:00:25.260
一緒に見る?

00:00:25.620 --> 00:00:29.460
サイバーセキュリティが、あなたの安心を守る。クラウドフレア。

字幕付きの動画や音声として再生するには、以下の記事にあるように VLC media player を使った方法があります。

image.png

Content-Length 7.5 MB 制限を回避する

いろいろな audio ファイルを調査する中で、以下のエラーが出ることがありました。

  • Error: 3006: Request is too large

Content-Length レスポンスヘッダが 75000 bytes を超えると、エラーが出るような挙動を確認しました。

audio ファイルがサイズ超過している場合、以下のようなコマンドでビットレートを調整することでサイズを縮小する、もしくはファイルを分割することを検討してください。

# ビットレートを調整
ffmpeg -i cf-pitch.mp3 -b:a 32k cf-pitch-32k.mp3
# ffmpeg -i cf-pitch.mp3 -b:a 48k cf-pitch-48k.mp3
# ffmpeg -i cf-pitch.mp3 -b:a 64k cf-pitch-64k.mp3
# ffmpeg -i cf-pitch.mp3 -b:a 72k cf-pitch-72k.mp3
# ffmpeg -i cf-pitch.mp3 -b:a 96k cf-pitch-96k.mp3
# ffmpeg -i cf-pitch.mp3 -b:a 112k cf-pitch-112k.mp3
# ffmpeg -i cf-pitch.mp3 -b:a 128k cf-pitch-128k.mp3
# ffmpeg -i cf-pitch.mp3 -b:a 160k cf-pitch-160k.mp3
# ffmpeg -i cf-pitch.mp3 -b:a 192k cf-pitch-192k.mp3
# ffmpeg -i cf-pitch.mp3 -b:a 256k cf-pitch-256k.mp3
# ffmpeg -i cf-pitch.mp3 -b:a 320k cf-pitch-320k.mp3

# 圧縮率の高いファイル形式に変更
ffmpeg -i audio.mp3 -vn -map_metadata -1 -ac 1 -c:a libopus -b:a 12k -application voip audio.ogg

# 時間を 50 分で切る
ffmpeg -i audio.mp3 -b:a 16k -t 00:50:00 audio-16k-50m.mp3

タイムアウトによる推論時間制限を回避する

Whisper による推論時間が約 2 分を超えると、以下のエラーが出ることがありました。

  • Error: 3007: Request timeout

audio ファイルの長さで言うと、約 50 分になります。

この場合、Cloudflare Workers AI による製品改善を期待する、もしくはファイルを分割することを検討してください。

image.png

ファイル分割に関して、segment の途中にならないような文脈をとらえた chunking についてはいくつか事前処理に使えるツールがあるようです。

initial_prompt による日本語認識改善

プロンプト(initial_prompt パラメータ)を使用すると、Whisper が生成するトランスクリプトの品質を向上させられる可能性があります。

ただし、改善できる度合いはある程度限られていると考えたほうが良さそうです。

プロンプト内では、専門用語を羅列する単語帳のような使い方が紹介されています。

You can use a prompt to improve the quality of the transcripts generated by the Whisper API. The model tries to match the style of the prompt, so it's more likely to use capitalization and punctuation if the prompt does too. However, the current prompting system is more limited than our other language models and provides limited control over the generated audio.

...

Because it wasn't trained with instruction-following techniques, Whisper operates more like a base GPT model. Keep in mind that Whisper only considers the first 224 tokens of the prompt.

Whisperのコンテキストのサイズは448です。これは、入力用と出力用のトークンの合計数であり、Whisperの実装では入力用には半分の224トークンまでに制約されています。そのため、未知語の数が多くなってきた場合は、prompt以外の方法を検討する必要があります。

例えば、日本語の文章をうまく理解させるために、「やさしい日本語」にあるような文章を initial_prompt パラメータに入れることで多少の日本語認識改善が見られました。

日本語の文字起こしの場合、initial_prompt パラメータには英単語等が含まれていない方が認識率が高かったです。

+ // やさしい日本語のサンプル文章
+ initial_prompt: '1 日の PM 2.5 の量が、 70 μg / m^2 を超えたときは、外に出ることをできるだけ少なくしましょう。そして、外での長い時間の激しい運動はできるだけ少なくしましょう。病気(呼吸器や循環器)の人、小さな子ども、お年寄りの方は、体調に気をつけましょう。',

まとめ

Cloudflare Workers AI では、すぐに AI を使い始めることができます。

これも Cloudflare の拠点に GPU が配備され、最寄りの拠点で推論をおこなえるインフラが整っているからです。

Workers の使いやすさに加えて、さまざまなコンポーネントを Bindings で追加するだけで連携できる点も魅力です。

@cf/openai/whisper-large-v3-turbo で日本語の文字起こしもそれなりに使えることがわかったので、事後処理に他の AI モデルを組み合わせる等、アイデアが膨らむところです。

これからも Cloudflare Workers AI の成長を見守っていきましょう。

0
0
0

Register as a new user and use Qiita more conveniently

  1. You get articles that match your needs
  2. You can efficiently read back useful information
  3. You can use dark theme
What you can do with signing up
0
0

Delete article

Deleted articles cannot be recovered.

Draft of this article would be also deleted.

Are you sure you want to delete this article?