Cloudflare Whisperで$0コストの多言語音声認識をChatbotに追加する
Chatbotを構築していて音声入力を追加したいが、Google Speech-to-Text、AWS Transcribe、OpenAI Whisper APIには課金したくない——そんなあなたは、すでに必要なものをすべて持っています。Cloudflareの無料プランの中に。
この記事では、Cloudflare Workers AI Whisper large-v3-turboを私のポートフォリオサイトのChatbotに統合し、99言語の音声認識を完全無料で実現した方法を詳しく解説します。また、本番環境で遭遇した2つのバグと、その正確な修正方法も共有します。
なぜCloudflare Workers AIなのか?
CloudflareはWorkers AIを通じて音声認識機能を提供しており、Cloudflareのグローバルエッジネットワーク上で動作します。無料プランには以下が含まれます:
- Workers AI推論:無料、制限は公式ドキュメントを参照(個人プロジェクトや小規模アプリに十分)
- コールドスタートなし:エッジノードで動作し、ユーザーに最も近い場所で実行
- APIキー管理不要:
env.AIを通じてWorkerに直接バインド - 99言語対応:中国語、日本語、韓国語、フランス語、スペイン語、アラビア語など
最大の利点:モデルをホストしたり、GPUインスタンスを管理したり、サードパーティAPIのレート制限を気にする必要がありません。すぐに使えます。
Whisper Base vs Whisper Large v3 Turbo:詳細比較
Cloudflare Workers AIは2つのWhisperモデルを提供しています。正しいモデルを選ぶことが重要です。
@cf/openai/whisper(ベース版)
オリジナルのWhisper baseモデル(約3,900万パラメータ)です。
メリット:
- 推論速度が速い——レイテンシに敏感なアプリケーションに最適
- リクエストあたりのリソース消費が少ない
- Cloudflare上で十分に検証済みで安定している
デメリット:
- 単語誤り率(WER)が高め、特に非英語言語で
- アクセント、専門用語、混合言語入力の認識が弱い
- audioパラメータ形式:
number[](Uint8Arrayを通常のJS配列に展開)
最適なユースケース: スピードが精度より重要な高トラフィックアプリ、または英語専用のユースケース。
@cf/openai/whisper-large-v3-turbo(Turbo版)
Whisper large-v3の軽量蒸留版(約8億900万パラメータ)で、large-v3より約2倍速く、精度の大部分を保持しています。
メリット:
- ベース版と比較してWERが約50%低減——中国語、日本語、韓国語などで大幅に改善
- 様々なアクセントに対して優れた多言語精度
- オプションパラメータ対応:
language、task(transcribe/translate)、vad_filter、beam_size - 豊富な出力:
text、word_count、WebVTTタイミング付きsegments
デメリット:
- ベース版より重い——リクエストあたりのレイテンシが若干高い
- audioパラメータ形式:Base64文字列(数値配列ではない——これが最初のバグの原因)
webm/opusコンテナを安定してデコードできない(これが2番目のバグの原因)
最適なユースケース: 多言語Chatbot、音声アシスタント、アクセシビリティツール、精度が重要な文字起こしパイプライン。
比較サマリー
| | @cf/openai/whisper | @cf/openai/whisper-large-v3-turbo |
|---|---|---|
| パラメータ数 | 約3,900万 | 約8億900万 |
| 対応言語 | 99言語 | 99言語 |
| 認識精度 | 良好 | 優秀 |
| 推論速度 | 最速 | 速い(large-v3より約2×) |
| audioパラメータ形式 | number[] | Base64文字列 |
| 対応コンテナ | webm、wav、mp3 | wav、mp3(webmは不安定) |
| 追加出力フィールド | textのみ | text、word_count、segments |
| Cloudflareコスト | 無料プラン | 無料プラン |
アーキテクチャ
構築したフルパイプライン:
ブラウザマイク
↓
MediaRecorder(webm/opus録音——ブラウザのデフォルト形式)
↓ 【クライアント側トランスコード】
AudioContext.decodeAudioData() → webm/opusをデコード
↓
encodeWAV() → 16-bit PCM WAV(モノラル、ネイティブサンプルレート)
↓ HTTP POST multipart/form-data
/api/transcribe(Next.js Edge Route on Cloudflare Pages)
↓
getRequestContext().env.AI(Cloudflare AIバインディング)
↓
btoa() → 8192バイトのチャンクでBase64エンコード
↓
env.AI.run('@cf/openai/whisper-large-v3-turbo', { audio: base64 })
↓
{ text: "文字起こし結果" } → Chatbot入力欄に反映
本番で遭遇した2つのバグ
バグ1:エラーコード5006 — タイプミスマッチ
@cf/openai/whisperからwhisper-large-v3-turboに切り替えた後、APIがエラー5006を返しました。
根本原因: ベースモデルが期待する古い形式audio: [...audioBytes](数値配列)をそのまま使い続けたことです。turboモデルはBase64文字列を要求します。2つのモデルは入力スキーマが完全に異なります——しかしドキュメントには明記されていませんでした。
修正方法: サーバー側でbtoa()を使ってチャンク処理し、Uint8ArrayをBase64文字列にエンコードしてから渡します。
バグ2:エラーコード3030 — 音声ファイルのデコード失敗
Base64形式を修正した後、エラー3030が発生しました。
根本原因: ブラウザはwebm/opus形式で録音します。Base64エンコードは正しかったのですが、turboモデルがwebm/opusコンテナをデコードできませんでした。Cloudflare Whisper turboが安定してサポートするのはWAVとMP3のみです。
修正方法: ブラウザ側でAudioContext.decodeAudioData()を使ってwebm/opusをデコードし、カスタムencodeWAV()で16-bit PCM WAVに再エンコードしてアップロードします。WAVはWhisperで最も普遍的にサポートされる入力形式です。
重要な注意点とヒント
-
export const runtime = 'edge'は必須です。 これがないと、getRequestContext()はCloudflare Pages上で何も返しません。 -
Edge Runtimeには
Bufferがありません。 Base64エンコードにBuffer.from(bytes).toString('base64')は使えません。btoa()とチャンク処理を使用し、大きな音声ファイルでコールスタックオーバーフローを防いでください。 -
turboとbaseモデルの
audioフィールドの型が異なります。 この違いはドキュメントに明記されていません——エラーと実験から発見しました。 -
AudioContextは必ず閉じてください。 ブラウザは同時に存在できるAudioContextインスタンス数に上限があります。デコード後は必ずawait audioCtx.close()を呼び出してください。 -
空の録音に注意してください。 ユーザーが誤ってマイクをタップしてすぐ離した場合、
decodeAudioDataは空のblobに対して例外をスローします。blob.size < 1000をチェックして早期リターンしてください。 -
Base64は約33%のサイズ増加をもたらします。 10秒の音声録音(約160KB生PCM)はBase64後に約215KBになり、Cloudflareの制限内に収まります。
-
iOSはユーザージェスチャが必要です。
AudioContextを作成するためにonPointerDown(タイマーやuseEffectではなく)を使用してください。
最終結果
このパイプラインを実装後、私のChatbotは以下をサポートします:
- 長押しして話す:マイクボタンを押したまま話し、離したら文字起こし
- タップ切り替え:一度タップして録音開始、話し終えたらもう一度タップして文字起こし
- 99言語:中国語、日本語、韓国語、英語などで優れた認識精度
- ゼロコスト:Cloudflareの無料プラン内で完結
- サードパーティAPIキー不要:すべてCloudflareエッジで動作
多言語AIプロダクトを構築していて音声入力が必要な場合、Cloudflare Workers AI Whisperが答えです。私が遭遇した2つのバグはドキュメントに明記されていません——この記事が数時間のデバッグを節約するお役に立てれば幸いです。
完全な実装はelvisli.caで公開中です。

