2026/08/14バージョン6.5でもういいっぱよね?(EN/JP6.4)

07:50

著者: かっぱ

カテゴリー: ゲーム, IT技術ネタ?, 雑記, パソコン・インターネット

タグ:OBS, リアルタイム翻訳, Cloudflare Workers AI, AI Gateway, Whisper, Llama3, 音声認識, 字幕自動生成, Python, 配信ツール, 無料AI, 個人開発, ハルシネーション対策, VAD, 省エネAI

おぱよう かっぱだっぱ(o’Θ’o)ノ))フリフリ
いい加減PC側からできることは一通り試したっぱので (PCに負荷をかけず翻訳結果を字幕にするコレ)
次回はブラウザーに音声認識を代行させてトークンをさらに節約させて低負荷で動作させられるものかどうかを検証する予定でいるっぱ
大体は問題ないっぱがたまぁにアンチチートの規約に不穏な事が書いてあるものもあるご時世だからの これにもいえるし今後のものにしてもくれぐれもゲーム側のルールに違反しないように気をつけてどうぞっぱ たまに グレーゾーン扱いしてる枠が多すぎるゲームもあるようなので正直 おいらにこのゲームは大丈夫? あのゲームは大丈夫といわれても┐(゜Θ゜)┌ェエエだっぱ

特にえげつないのは ゲーム会社が問題視してないと返事が来ても アンチチートの会社がそうではない場合もあるので 特にアプデでダメになった系はどうしろとなるからの ┌┛┌┛ズコ!

いちいちそれらの対応の為に長い時間を取るのは無理と判断したっぱ(ただちには) お金もらってやってるとかなら(Θ゜*)ゞエヘッ しかたないっぱねぇと 聞いてくるっぱが
EAC(EpicGames)に関しては ゲストIDで問い合わせをした場合 アカウントを取得してEAC向けの専用の議論場所に誘導するお返事のメールが日本語で届いたっぱ (o’Θ’))ゥンゥン 参考になったっぱ
現状使う人もそうおらんし (外人が配信に突撃してきて困惑している人の補助の目的は達しているのでOK) どこぞのAIにここの生成物をコピペして 業者発注してサポートしてもらったらいくら? そういえばどんぐらいの手間がかかってるかもわかるだろうからの (おいらがもの好きかつお金の問題よりコミュニケーションの問題を著しく毛嫌いしていてコミュニケーションできない人々を悪用してルール無用の真似をする一部のボケナス対策に必要と思ったので用意しただけだからの・・)
話がそれたっぱ 最新版のReadMeをはっておくっぱ 一番最後に日本語版と英語版のファイルおいておくっぱよ

次回は余裕があればブラウザで動くよ版っぱ(ボソ


OBS + Cloudflare Workers AI + AI Gateway 字幕翻訳スクリプト v6.5 (0810版)

OBS配信でリアルタイム字幕翻訳を行うPythonスクリプト。Cloudflare Workers AIの無料枠(10,000 Neurons/日)で動作します。


📋 目次

  1. 概要
  2. 必要なもの
  3. Cloudflareアカウントのセットアップ
  4. 使い方
  5. OBS側の設定
  6. ユースケース
  7. Whisperモデル選択とNeuron消費
  8. トラブルシューティング
  9. 機能一覧
  10. v6.5の修正内容
  11. コード構造解説(v6.5でコメント削除・README移管)
  12. バージョン履歴
  13. ライセンス
  14. 免責事項

✨ 概要

マイク音声または配信音声をリアルタイムで文字起こしし、翻訳してOBSのテキストソースに表示します。

  • 🎤 マイクモード: 自分の声を拾って翻訳(日本語→英語 / 英語→日本語 / 自動検出)
  • 🎮 配信モード: ゲーム・配信音声を拾って翻訳

📋 必要なもの

  • Python 3.10+
  • Cloudflareアカウント(無料プランでOK)
  • OBS Studio(テキストソース(GDI+)が必要)
  • pip install: sounddevice requests numpy scipy
pip install sounddevice requests numpy scipy

scipy は任意ですが、高品質なリサンプリングのために推奨されます。


☁️ Cloudflareアカウントのセットアップ

ステップ1: Cloudflareアカウントの作成

  1. Cloudflare でサインアップ
  2. Cloudflare Dashboard にログイン

ステップ2: Account IDの確認

  1. ダッシュボードのサイドバーでアカウントを選択
  2. Account ID(32文字の英数字)をコピー
  3. スクリプト内の ACCOUNT_ID に設定

ステップ3: APIトークンの作成

  1. API Tokens に移動
  2. Create Token をクリック
  3. Create Custom Token を選択
  4. 以下の権限を設定:
    • AccountWorkers AIRead
    • AccountAI GatewayRead, Edit
  5. Continue to summaryCreate Token
  6. トークンをコピー(一度しか表示されません)

ステップ4: AI Gatewayの作成

  1. AI Gateway に移動
  2. Create Gateway をクリック
  3. 名前を入力(例: default
  4. Create をクリック

💡 自動作成: APIリクエストでGateway IDに default を指定すると、最初のリクエスト時に自動作成されます。

Guardrails: ON or OFF?

対象 Guardrails NGワードリスト 理由
日本語話者 OFF(推奨) カスタム200+語 Neuron節約。日本語のNG表現はカスタムフィルタでカバー
英語話者 ON(推奨) 不要 Cloudflareのネイティブコンテンツモデレーションが英語に高精度

日本語話者: GuardrailsをOFFにしてください。スクリプトに日本語コンテンツ向けの200+語のカスタムNGフィルタが含まれており、Neuronを節約しながら不適切コンテンツをフィルタします。

英語話者: AI GatewayダッシュボードでGuardrailsをONにしてください。Cloudflareがネイティブにコンテンツモデレーションを処理します。Neuron消費はわずかに増加しますが、英語のNG検出はより精度が高くなります。

ステップ5: AI Gatewayキャッシュの有効化(★必須 — これをONにしないとNeuron節約なし)

  1. AI Gateway でゲートウェイを選択
  2. Settings を開く
  3. Cache ResponsesON に設定
  4. デフォルトキャッシュTTLを 300秒(5分)に設定

⚠️ これをONにしないとキャッシュが機能しません。 cf-aig-cache-ttl ヘッダーだけでは効果がありません。ダッシュボードで「Cache Responses」を有効にする必要があります。

💡 AI Gatewayは完全に無料。 キャッシュ・ログ機能ともに無料で追加課金なし。追加サブスクリプション不要です。

スクリプトは cf-aig-cache-ttl ヘッダー(TRANSLATE_CACHE_TTL = 300)と cf-aig-cache-key ヘッダー(翻訳方向+ソーステキストのみをキーに使用し、プロンプトのフォーマットに関わらず同じフレーズでキャッシュヒット)も指定しています。

v6.4キャッシュキー改善: v6.3までは cf-aig-cache-keyf"{direction}:{text}" をそのまま使っており、日本語テキストがHTTPヘッダーに直接入っていました。v6.4以降はSHA-256ハッシュ(64文字ASCII)を使用し、安全かつ同一性を保証します。

キャッシュログ: スクリプトは [Cache MISS][Cache Hit] の両方をログ出力するので、キャッシュ動作を確認できます。[Cache MISS] ばかりの場合は、ダッシュボードで「Cache Responses」がONになっているか確認してください。

ステップ6: スクリプトに認証情報を設定

環境変数を使用する場合(推奨):

# Windows (コマンドプロンプト)
set CF_API_TOKEN=あなたのトークン

# Windows (PowerShell)
$env:CF_API_TOKEN = "あなたのトークン"

# Mac / Linux
export CF_API_TOKEN=あなたのトークン

またはスクリプトに直接入力:

CLOUDFLARE_API_TOKEN = os.environ.get("CF_API_TOKEN", "cfat_paste_your_token_here")

ACCOUNT_IDGATEWAY_ID も設定:

ACCOUNT_ID = "your_account_id"
GATEWAY_ID = "default"  # 作成したゲートウェイ名

ステップ7: Workers AIアクセスの確認

  1. Workers AI に移動
  2. モデルリストが表示されることを確認
  3. Usage タブでNeuron消費を確認

💰 料金(心配不要)

項目 コスト
AI Gateway作成・使用 無料
AI Gatewayキャッシュ機能 無料
AI Gatewayログ機能 無料
追加サブスクリプション 不要

Workers AI(Whisper + LLM翻訳)の料金:

プラン 無料枠 上限超過 自動課金
Free(現在) 10,000 Neurons/日 無料 エラーで停止 なし
Paid ($5/月) 10,000 Neurons/日 無料 $0.011 / 1,000 Neurons あり

Freeプランで使えます。 1日10,000 Neuronsまで無料です。 ✅ 上限超過で自動課金されません。 エラーで停止するだけです。 ⚠️ 課金には意図的にWorkers Paid($5/月)へのアップグレードが必要です。


🚀 使い方

python obs_subtitle_translator_0810_v6_5.py

起動時に以下を選択します:

  1. モード: マイク (1) または 配信 (2)
  2. 言語: 翻訳方向 (1-5)
  3. デバイス: デフォルト (d) または 一覧 (l) または デバイス番号
  4. ジャンル: ゲーム/雑談/技術/音楽/なし/かっぱ (1-6)
  5. レイテンシー: 短縮(3秒) / 通常(5秒) / 精度優先(8秒)
  6. Whisperモデル: 標準 (1) または 高精度 (2)

⚠️ デバイス番号の警告: デフォルトデバイス番号(DEFAULT_MIC_DEVICE = 7, DEFAULT_GAME_DEVICE = 61)は作者のマシン固有のものです。あなたのデバイス番号は異なります。 デバイス選択プロンプトで l を入力して利用可能なデバイスを一覧表示し、正しいものを選んでください。


📺 OBS側の設定

  1. OBS Studioを開く
  2. ソース+テキストソース(GDI+)
  3. テキストソースのプロパティを開く
  4. ファイルから読み込む にチェック
  5. output_mic.txt または output_game.txt を参照して選択
  6. エンコーディングUTF-8 に設定
  7. フォント、サイズ、色を調整

字幕は自動的に更新されます。15秒間無音が続くと字幕が消去されます。

⚠ マイクモード使用時の注意

  • 起動直後の約30秒は黙って待つ(ノイズフロア学習中)
  • 学習中はマイクに触れない(ノイズフロアが跳ね上がる)
  • [ノイズゲート確定] のログが出たら話し始めてOK
  • 配信中と同じ環境(BGMあり)で学習するのが推奨
  • 終了は Ctrl+C(outputファイルが空になります)

💡 ユースケース

例1: 日本語配信者 → 英語字幕

モード: 1 (マイク)  言語: 1 (日本語→英語)  レイテンシー: 2 (通常 5秒)

例2: 英語ゲーム配信 → 日本語字幕

モード: 2 (配信)  言語: 1 (英語→日本語)  レイテンシー: 3 (精度優先 8秒)

例3: 双方向自動検出(日本語・英語混在配信)

モード: 1 (マイク)  言語: 3 (自動検出)  レイテンシー: 2 (通常 5秒)

例4: 英語のみモード(日本語スルー)

モード: 2 (配信)  言語: 4 (英語のみ、日本語スルー)

例5: かっぱ配信(語彙ヒント)

「かっぱ配信」は配信者が語尾に「っぱ」をつける日本のVTuber/配信スタイルです。ジャンル6はこれらのパターンをWhisperの語彙ヒントとして追加し、認識精度を向上させます。

モード: 1 (マイク)  言語: 1 (日本語→英語)  ジャンル: 6 (かっぱ)

例6: 技術配信(技術用語)

モード: 1 (マイク)  言語: 1 (日本語→英語)  ジャンル: 3 (技術/プログラミング)

例7: 低レイテンシモード

モード: 1 (マイク)  言語: 1 (日本語→英語)  レイテンシー: 1 (短縮 3秒)

例8: ノイズの多い環境向け精度優先

モード: 2 (配信)  言語: 1 (英語→日本語)  レイテンシー: 3 (精度優先 8秒)

例9: 高精度Whisperモデル

モード: 1 (マイク)  言語: 1 (日本語→英語)  Whisperモデル: 2 (高精度)

🎯 Whisperモデル選択とNeuron消費

モデル比較

モデル Neurons/分 精度 temperature=0.0 ハルシネーション率
標準 (@cf/openai/whisper) 41.14 ✅ 対応
高精度 (whisper-large-v3-turbo) 46.63 ❌ 非対応 やや高

高精度モデルは temperature/prompt パラメータ非対応で、base64 JSON形式で音声を送信します。 temperature=0.0(決定的出力)がないため、高精度モデルはハルシネーションがやや多くなる可能性があります(無音から「Thank you for watching」等が出力される等)。

Neuron消費の内訳

実際の配信テスト(ゲーム配信44分、8秒チャンク、自動検出モード)に基づく:

コンポーネント Neurons/44分 全体比
Whisper(音声認識) ~1,587 93%
翻訳(LLM) ~113 7%
合計 ~1,700 100%

重要: WhisperがNeuron消費の 93% を占めます。翻訳はわずか7%。 翻訳コスト削減(キャッシュ等)は全体で最大3-5%の節約。 実行時間を延ばす最も効果的な方法は、Whisper呼び出しを減らすこと(VADフィルタリング)。

推定実行時間(10,000 Neurons/日 無料枠)

シナリオ モデル Neurons/分 推定実行時間
ゲーム配信(常時会話) 標準 ~38 約4.4時間
ゲーム配信(常時会話) 高精度 ~43 約3.9時間
雑談配信(会話に間あり) 標準 ~25 約6.6時間
マイクモード(静か、VAD 50-70%フィルタ) 標準 ~13 約13時間

VAD棄却率: ゲーム配信 ~13%(常に音声あり)、マイクモード ~50-70%(無音フィルタ)。 VAD棄却率が高い = Whisper呼び出しが少ない = 実行時間が長い。

キャッシュ効果

キャッシュ種別 機能 Neuron節約
AI Gatewayキャッシュ (cf-aig-cache-ttl) 同一翻訳リクエストをキャッシュ 全体 ~3-5%(翻訳のみ)
Prompt Caching (x-session-affinity) 共通プロンプトプレフィックスをキャッシュ 全体 ~1-2%
カスタムキャッシュキー (cf-aig-cache-key) ソーステキストのみをキーに使用 (v6.3) 類似フレーズのヒット率向上
SHA-256キャッシュキー (v6.4) 日本語テキストをハッシュ化して安全にキャッシュ 同上(安全性向上)

重要: AI Gatewayキャッシュを機能させるには、AI Gatewayダッシュボード設定で「Cache Responses」を有効にする必要があります。これがないと cf-aig-cache-ttl ヘッダーは効果がなく、キャッシュヒットも発生しません。

スクリプトは [Cache MISS][Cache Hit] の両方をログ出力するので、キャッシュ動作を確認できます。[Cache MISS] ばかりの場合は、ダッシュボード設定を確認してください。


🔧 トラブルシューティング

症状 原因 解決策
話声を拾わない VAD事前チェック閾値が高すぎる VAD_PRECHECK_THRESHOLD を 3.0→2.0 に下げる
ノイズを拾いすぎる VAD事前チェック閾値が低すぎる VAD_PRECHECK_THRESHOLD を 3.0→5.0 に上げる
ゲーム音声を拾わない VAD閾値が高すぎる VAD_THRESHOLD_GAME を 400→300 に下げる
ゲーム音声を拾いすぎる VAD閾値が低すぎる VAD_THRESHOLD_GAME を 400→500 に上げる
APIエラー 401 トークン権限不足 Workers AI Read + AI Gateway Read/Edit 権限を確認
APIタイムアウト ネットワーク遅延 API_TIMEOUT を 30→60 に上げる
字幕が文字化け OBSのエンコーディング テキストソース(GDI+)でUTF-8を指定
起動時に何も拾わない ノイズ学習中(正常) 30秒待つ。[ノイズゲート確定] 後に話してOK
[Cache Hit] が出ない AI Gateway Cache Responses がOFF ダッシュボードでCache ResponsesをON → TTL 300秒
scipyエラー scipy未インストール pip install scipy(なくても動作しますが精度が落ちます)
[Neuron上限到達] で停止 10,000 Neurons/日の無料枠を使い切った 翌日まで待つ、またはWorkers Paid($5/月)にアップグレード

📦 機能一覧

音声認識・翻訳

  • Whisper音声認識(標準 / 高精度 / 英語専用の自動選択)
  • LLM翻訳(llama-3.1-8b-instruct-fast)
  • AI Gatewayルーティング(キャッシュ・ログ・レート制限)
  • Prompt Caching(x-session-affinity、TTFT短縮+Neuron節約)
  • トークン使用量表示([Token] in=X out=Y、Neuron消費監視)

ノイズ除去・VAD

  • 動的ノイズゲート(マイクモードのみ、起動時に30秒学習)
  • 周波数VAD(200-3400Hz帯域パワーで人の声を判定、BGM/SFXをフィルタ)
  • FFT前エネルギー事前チェック(低エネルギーチャンクのFFTをスキップ、CPU削減)
  • 無音トリミング(前後の無音をカットしてAPIペイロード削減)
  • 音声正規化(DCオフセット除去 + ピークゲイン調整)

ハルシネーション検出

  • 短文スキップ(3文字以下・1単語以下、jaモード時のみ — v6.5修正)
  • 繰り返し検出(同一3文字パターンが8回以上)
  • プロンプト漏出検出(「厳守ルール」等)
  • 言語固有フィルタ(jaモード時のみ):
    • ハングル / キリル / ギリシャ / タイ / 中国語(簡体字)
    • 特殊ラテン(トルコ) / 北欧系文字
    • ヨーロッパ言語(ドイツ語・フランス語・スウェーデン語・オランダ語・スペイン語・イタリア語)
    • 漢字のみ短文
    • 英語ハルシネーション(jaモードで英語のみが出力された場合)

フィルタ・品質管理

  • NGワードフィルタ(200+語、単語境界 \b 対応、マスク/スキップ選択可)
  • 翻訳入力のNGフィルタバイパス(表示用はフィルタ済み、翻訳用は生テキストで文脈保持)
  • 重複スキップ(Jaccard類似度 85%以上)
  • 翻訳ループ検出・自動切り詰め
  • 翻訳安全拒否検出(「I cannot provide」等を検出、元テキストを使用)
  • 翻訳失敗検出(ja_to_enで日本語のまま返却された場合、元テキストを使用)

録音・パイプライン

  • InputStream連続録音(PortAudioコールバック、ギャップレス)
  • リングバッファ(deque(maxlen=...) で古いデータを自動破棄、ブロック数ベースで計算 — v6.4修正)
  • 非ブロッキングパイプライン(録音スレッド × APIワーカースレッド分離)
  • HTTPセッション再用(TCP/TLSハンドシェイク1回のみ、サイクル毎100-300ms節約)
  • Atomic write(テンポラリファイル → os.replace() でOBS読み込み破損を防止)
  • APIリトライ(Whisper・翻訳APIとも最大2回)
  • Guardrailsエラーハンドリング(コード2016/2017を検出してスキップ)
  • 429エラーgraceful shutdown(Neuron上限到達時に安全に停止、無限リトライ防止 — v6.5修正)

モード・設定

  • マイクモード / 配信モード
  • 双方向自動検出([JA] / [EN] / [JA?] タグ付き)
  • 英語のみモード(日本語スルー)
  • 日本語以外すべてモード(日本語スルー)
  • レイテンシモード(3秒 / 5秒 / 8秒)
  • ジャンルヒント(ゲーム/雑談/技術/音楽/かっぱ)
  • 翻訳ジャンルヒント(Llama system promptに注入、直訳癖を軽減)
  • Whisperモデル選択(標準 / 高精度)
  • 15秒自動消去
  • 環境変数対応(CF_API_TOKEN

🆕 v6.5の修正内容

修正①: check_vad で voice_mask 空配列時のNaN発生を防止 ★★★

問題: check_vad() 関数内で voice_mask = (freqs >= 200) & (freqs <= 3400) の結果が全False(200-3400Hzに周波数ビンが存在しない極端に短いサンプル)の場合、np.abs(fft[voice_mask]).mean()NaN を返す。NaN < vad_thresholdFalse となり、VADを通過してしまいノイズがWhisperに送られていた。

修正: np.any(voice_mask) で空配列を事前チェックし、空の場合はVAD不合格として False を返す。

# 修正前
voice_mask = (freqs >= 200) & (freqs <= 3400)
voice_power = np.abs(fft[voice_mask]).mean()

# 修正後
voice_mask = (freqs >= 200) & (freqs <= 3400)
if not np.any(voice_mask):
    return False
voice_power = np.abs(fft[voice_mask]).mean()
  • 極端に短いサンプルや低サンプルレート環境でNaNによるVADすり抜けを防止
  • 正常な音声には影響なし(通常のサンプルレートでは200-3400Hzに必ずビンが存在する)

修正②: 短文フィルタをjaモードのみに限定 ★★★

問題: detect_hallucination() の短文スキップフィルタ(3文字以下・1単語以下・かな/漢字なし)が whisper_language に関わらず常に有効だった。英語モード(whisper_language == "en")でも "Yes"(3字), "OK"(2字), "Hi"(2字), "No"(2字) などの正当な短い英語発話がハルシネーションとして破棄されていた。

修正: whisper_language == "ja" の場合のみ短文フィルタを適用する。

# 修正前
if len(stripped) <= 3 and len(stripped.split()) <= 1 and not _KANA_RE.search(stripped) and not _CJK_RE.search(stripped):
    return True

# 修正後
if whisper_language == "ja" and len(stripped) <= 3 and len(stripped.split()) <= 1 and not _KANA_RE.search(stripped) and not _CJK_RE.search(stripped):
    return True
  • 英語モード・autoモードで正当な短い英語発話が破棄されなくなる
  • 日本語モードでは従来通りハルシネーション防止が有効

修正③: translate() でlist型レスポンスに対応 ★★☆

問題: translate() 関数のレスポンス処理で isinstance(response, str)isinstance(response, dict) はチェックしていたが、list 型が返った場合の処理がなかった。else ブロックで str(response) が実行され、list[...] という文字列表現になってしまっていた。

修正: isinstance(response, list) の分岐を追加。listの最初の要素がdictの場合は response/text キーを探し、そうでない場合は要素を文字列として扱う。

# 追加した分岐
elif isinstance(response, list) and response:
    first = response[0]
    if isinstance(first, dict):
        val = first.get("response")
        if val is None:
            val = first.get("text", "")
        translated = str(val).strip() if val else ""
    else:
        translated = str(first).strip() if first else ""
  • Workers AI APIの仕様変更等でlist型レスポンスが返った場合でも正しく翻訳結果を抽出
  • 既存のstr/dict処理には影響なし

修正④: コメント削除・README移管 ★★☆

問題: v6.4のpyファイルには約80行のヘッダコメント(機能一覧・使い方・トラブルシューティング・バージョン履歴等)が含まれており、ファイルサイズが肥大化していた。

修正: pyファイルから全コメントを削除し、ヘッダに4行の最小限の参照のみ残した。削除した内容は本READMEに統合・移管。

# pyファイルのヘッダ(v6.5)
# OBS + Cloudflare Workers AI + AI Gateway 字幕スクリプト v6.5 (0810版)
# 詳細な使い方・設定・トラブルシューティングは README_v6_5.md を参照
# Python 3.10+, pip install sounddevice requests numpy scipy
# MIT License — Copyright (c) 2026
  • pyファイルのサイズを約15%削減
  • 説明文の重複を解消(READMEが唯一の情報源)
  • コードの可読性向上(実行に不要なコメントが排除)

修正⑤: 429エラー(Neuron上限到達)時のgraceful shutdown ★★★

問題: 10,000 Neurons/日の無料枠を使い切るとAPIが429エラーを返すが、従来はこれを一時エラーとしてリトライし続けた。実配信ログでは上限到達後も数十回の無意味なリトライを繰り返し、コンソールが429エラーメッセージで埋め尽くされていた。

修正: モジュールレベルの _quota_exhausted イベントフラグを追加。transcribe() / translate() で429を検出したらフラグをセットし、リトライせず即座にリターン。worker_thread_fn()main() のループがフラグを検知してgraceful shutdownする。

# フラグ定義
_quota_exhausted = threading.Event()

# transcribe() / translate() 内
if resp.status_code == 429:
    print("[Neuron上限到達] 10,000 Neurons/日の無料枠を使い切りました。")
    _quota_exhausted.set()
    return ""

# worker_thread_fn() 内
if _quota_exhausted.is_set():
    print("[Neuron上限到達 - 処理を停止します]")
    shutdown_event.set()
    break

# main() ループ内
if _quota_exhausted.is_set():
    print("=== Neuron上限到達 — 停止中... ===")
    shutdown_event.set()
    break
  • 上限到達後の無意味なリトライを完全排除
  • コンソールが429エラーで埋め尽くされる問題を解消
  • InputStream・ワーカースレッド・メインループが連携して安全に停止
  • ユーザーに分かりやすいメッセージを表示(Workers Paidプランへの案内付き)

📖 コード構造解説(v6.5でコメント削除・README移管)

v6.5ではpyファイルからコメントを削除しました。以下にコード構造を解説します。

定数セクション(ファイル上部)

定数 説明
CLOUDFLARE_API_TOKEN APIトークン(環境変数 CF_API_TOKEN から取得)
ACCOUNT_ID / GATEWAY_ID CloudflareアカウントID / AI Gateway名
DEFAULT_MIC_DEVICE / DEFAULT_GAME_DEVICE デフォルトデバイス番号(作者のマシン固有 — 要変更)
WHISPER_MODEL_* Whisperモデル名(標準/英語専用/高精度)
TRANSLATE_MODEL 翻訳LLMモデル名(llama-3.1-8b-instruct-fast)
TRANSLATE_CACHE_TTL 翻訳キャッシュTTL(300秒)
API_TIMEOUT APIタイムアウト(30秒)
MAX_LINES / AUTO_HIDE_SEC 最大表示行数(2) / 自動消去秒数(15)
VAD_THRESHOLD_MIC / VAD_THRESHOLD_GAME VAD閾値(マイク100 / 配信400)
VAD_PRECHECK_THRESHOLD FFT前エネルギー事前チェック閾値(3.0)
NG_WORDS / NG_WORDS_BOUNDED NGワードリスト(部分一致 / 単語境界)

関数一覧

関数 説明
select_mode() 起動時の対話式セットアップ(モード・言語・デバイス・ジャンル・レイテンシー・モデル選択)
get_whisper_model() 言語に応じたWhisperモデルを返す(en→tiny-en、それ以外→標準)
get_headers() APIリクエストヘッダーを構築(認証・キャッシュTTL・session affinity・cache key)
check_ng_words() NGワードフィルタ(マスクまたはスキップ)
normalize_audio() DCオフセット除去 + ピークゲイン調整
trim_silence() 前後の無音をカット
detect_language_simple() テキストの言語を簡易判定(かな→ja、簡体字→zh、漢字のみ→zh_or_kanji_only、その他→other)
detect_hallucination() ハルシネーション検出(短文/繰り返し/プロンプト漏出/言語固有フィルタ)
transcribe() Whisper APIで音声をテキスト化(リトライ2回・ガードレールエラー処理・ハルシネーションフィルタ)
truncate_repeated_translation() 翻訳出力のループ検出・切り詰め
translate() LLM APIで翻訳(キャッシュ・リトライ・安全拒否検出・翻訳失敗検出)
similarity() Jaccard類似度による重複判定
update_output_file() Atomic write(テンポラリファイル→os.replace())でOBS出力ファイルを更新
audio_callback() PortAudioコールバック(リングバッファに音声ブロックを追加)
check_vad() 周波数VAD(200-3400Hz帯域パワーで人の声を判定、FFT前エネルギー事前チェック付き)
capture_one_chunk() リングバッファから1チャンク分の音声を取得・ノイズゲート・VAD・リサンプリング・WAVエンコード
capture_one_chunk_fallback() InputStream失敗時のフォールバック(sd.rec() で直接録音)
worker_thread_fn() API処理スレッド(音声キューから取得→文字起こし→NGフィルタ→翻訳→OBS出力)
main() メイン関数(セットアップ→InputStream起動→チャンク取得ループ→自動消去)

パイプライン構造

[マイク/配信音声]

  InputStream (PortAudio callback)  ← 連続録音・ギャップレス

  Ring Buffer (deque, maxlen=ブロック数)  ← 20秒分保持

  capture_one_chunk()  ← ノイズゲート(mic) → VAD → 正規化 → 無音トリミング → リサンプリング → WAV

  Audio Queue (maxsize=5)  ← 録音スレッドとAPIスレッドの分離

  worker_thread_fn()  ← Whisper API → ハルシネーション検出 → NGフィルタ → 翻訳API → OBS出力

  output_mic.txt / output_game.txt  ← Atomic write → OBS Text Source (GDI+)

英語版との違い

英語版(obs_subtitle_translator_0810_v6_5_en.py)は日本語版と機能的に同等ですが、以下の違いがあります:

  • 言語固有ハルシネーションフィルタ: 日本語版ではjaモード時にハングル・キリル・ギリシャ・タイ・中国語・ヨーロッパ言語等の検出が有効。英語版ではこれらを削除し、多言語配信者の正当な発話が破棄されないようにしている(汎用フィルタ=短文・繰り返し・プロンプト漏出のみ残存)
  • UI言語: プロンプト・ログメッセージが英語
  • 短文フィルタ: v6.5でjaモードのみに限定したため、英語版では短文フィルタが実質無効化(英語の短い発話 “Yes”, “OK” 等が破棄されない)

📜 バージョン履歴

v6.5 (0810)

  • check_vad で voice_mask 空配列時のNaN発生を防止np.any() 事前チェック追加)
  • 短文フィルタをjaモードのみに限定(英語モードで “Yes”, “OK”, “Hi”, “No” 等が破棄される問題を修正)
  • translate() でlist型レスポンスに対応(listの最初の要素から翻訳結果を抽出)
  • 429エラー(Neuron上限到達)時のgraceful shutdown(無限リトライを防止、安全に停止)
  • pyファイルからコメント削除・README移管(ファイルサイズ約15%削減、説明文の重複解消)

v6.4 (0809)

  • Cache Key を SHA-256 ハッシュ化(日本語テキストがHTTPヘッダーに直接入る問題を修正)
  • 漢字のみテキストをautoモードで捨てない([JA?] タグ付きで ja_to_en 処理)
  • Ring Buffer の maxlen をブロック数で計算(メモリ浪費を修正)
  • Token Usage 取得を型安全化(isinstance チェック + or {} 追加)
  • 翻訳入力のNGフィルタをバイパス(表示用はフィルタ済み、翻訳用は生テキストを渡して文脈破壊を防止)
  • 翻訳system promptにジャンルヒントを注入(直訳癖・ゲーム用語の誤訳を軽減、起動ログに 翻訳ジャンルヒント: あり/なし 表示を追加)

v6.3 (0805)

  • 言語固有ハルシネーションフィルタを whisper_language == "ja" 時のみ有効化(auto/enモードで多言語対応)
  • イタリア語ハルシネーション検出を追加
  • カスタムキャッシュキー(cf-aig-cache-key)追加 — 翻訳方向+ソーステキストのみをキーにしてヒット率向上
  • [Cache MISS] ログ追加([Cache Hit] と併せてキャッシュ動作確認用)
  • Neuron消費内訳・推定実行時間表をREADMEに追加
  • デバイス番号警告、かっぱ配信説明、多言語ユースケースをREADMEに追加

v6.2 (0805)

  • 翻訳API Prompt Caching(x-session-affinity)追加
  • VAD_PRECHECK_THRESHOLD 50.0→3.0 に調整(ハルシネーション削減)
  • VAD_THRESHOLD_MIC 50→100 に調整(微弱ノイズ排除)
  • かっぱ配信プロンプト強化(っぱ変換フレーズ追加)
  • Whisperモデル選択機能追加(標準/高精度)
  • whisper-large-v3-turbo対応(base64 JSON形式・temperature/prompt非対応)
  • 翻訳APIトークン使用量表示追加

v6.1 (0802)

  • FFT前エネルギー事前チェック(CPU負荷削減)
  • 英語専用Whisperモデル自動選択
  • 翻訳API AI Gatewayキャッシュ
  • 周波数マスク事前計算
  • VAD判定FFTウィンドウ短縮

v6.0

  • InputStream + リングバッファ(連続録音)
  • 非ブロッキングパイプライン
  • NGワード正規表現の事前コンパイル
  • 翻訳APIリトライ / Atomic write / 環境変数化
  • HTTPセッション再用 / レイテンシモード選択
  • ガードレールエラー対応
  • ノイズゲート学習フレーム数の動的調整

📄 ライセンス

使用するAIモデルのライセンス(2026/08/10現在)

モデル 提供元 ライセンス 商用利用
@cf/openai/whisper OpenAI MIT License ✅ 可能
@cf/openai/whisper-tiny-en OpenAI MIT License ✅ 可能
@cf/openai/whisper-large-v3-turbo OpenAI MIT License ✅ 可能
@cf/meta/llama-3.1-8b-instruct-fast Meta Llama Community License ✅ 可能(月間7億ユーザー未満)

注意: 今後別のモデル(パートナーモデル等)に置き換える場合は、それぞれの利用規約・ライセンスを確認してください。本スクリプトは2026/08/10時点で上記モデルを使用しており、すべてオープンソースライセンスで商用利用可能です。

本スクリプトのライセンス

MIT Licenseの下で公開します。自由に使用・改変・再配布してください。

MIT License

Copyright (c) 2026

Permission is hereby granted, free of charge, to any person obtaining a copy
of this software and associated documentation files (the "Software"), to deal
in the Software without restriction, including without limitation the rights
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
copies of the Software, and to permit persons to whom the Software is
furnished to do so, subject to the following conditions:

The above copyright notice and this permission notice shall be included in all
copies or substantial portions of the Software.

THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
SOFTWARE.

⚖️ 免責事項

  • 本スクリプトは現状のまま(AS IS)提供され、いかなる保証もありません
  • Cloudflare Workers AIの無料枠(10,000 Neurons/日)で動作しますが、利用量によっては上限に達する場合があります
  • 超過しても自動課金はされません(エラーで停止するだけです)
  • 課金には意図的にWorkers Paid($5/月)へのアップグレードが必要です
  • AIによる文字起こし・翻訳の精度は完全ではなく、誤認識が発生する場合があります
  • 配信での使用に伴ういかなる損害についても、作者は責任を負いません
  • Cloudflareのサービス仕様・料金・利用規約は変更される可能性があります。最新情報はCloudflare公式ドキュメントで確認してください
  • 使用するAIモデルのライセンス条件は変更される可能性があります。本スクリプトを改変して別のモデルを使用する場合は、必ず該当モデルのライセンスを確認してください

🔗 参考


OBS + Cloudflare Workers AI + AI Gateway Subtitle Script v6.5 (0810)

Real-time subtitle translation script for OBS streaming. Combines Cloudflare Workers AI (Whisper speech recognition + LLM translation) with AI Gateway for low-latency, low-cost subtitle generation. Runs entirely on the Cloudflare Workers AI free tier (10,000 Neurons/day).


Table of Contents

  1. Features
  2. Requirements
  3. Cloudflare Account Setup
  4. Running the Script
  5. OBS Configuration
  6. Use Cases
  7. Whisper Model Selection & Neuron Consumption
  8. Troubleshooting
  9. Feature List
  10. v6.5 Fixes
  11. Code Structure
  12. Version History
  13. License
  14. Disclaimer
  15. Differences from the Japanese Version

Features

Speech Recognition & Translation

Feature Description
Whisper speech recognition Uses @cf/openai/whisper (multilingual), @cf/openai/whisper-tiny-en (English-only, fast), or @cf/openai/whisper-large-v3-turbo (high-accuracy) on Cloudflare Workers AI
LLM translation Translates via @cf/meta/llama-3.1-8b-instruct-fast. Supports Japanese to English, English to Japanese, bidirectional auto-detect
AI Gateway routing All API requests go through AI Gateway for caching, logging, and rate limiting
Prompt Caching x-session-affinity header caches common prefix for reduced TTFT + Neuron savings (v6.2+)
Token usage display [Token] in=X out=Y shows real-time Neuron consumption (v6.2+)

Noise Removal & VAD

Feature Description
Dynamic noise gate Learns ambient noise for 30 seconds at startup, auto-sets noise floor (mic mode only)
Frequency VAD Judges human voice by 200-3400Hz band power. Filters BGM/SFX
Pre-FFT energy check Skips FFT for low-energy chunks (CPU savings). Threshold tuned to 3.0 (v6.2+)
Silence trimming Cuts leading/trailing silence to reduce API payload
Audio normalization DC offset removal + peak gain adjustment

Hallucination Detection

Feature Description
Short text skip Skips 1-word hallucinations <=3 chars (ja mode only – v6.5 fix)
Repetition detection Trims when same 3-char phrase repeats 8+ times
Prompt leak detection Detects prompt leaks, skips

Note: Language-specific filters (Hangul, Cyrillic, Greek, Thai, Chinese, European languages, Nordic, Special Latin) are intentionally removed in the English version. English-version users may want to transcribe/translate those languages, so filtering them out would drop valid transcriptions.

Filters & Quality Control

Feature Description
NG word filter 200+ NG words pre-compiled as regex. Word boundary and substring match variants
Translation input NG filter bypass Display text is filtered, raw text passed to translation to preserve context (v6.4)
Duplicate skip Skips if >=85% similar to previous transcription
Translation loop detection Trims when same phrase repeats in translation output
Translation safety refusal detection Detects “I cannot provide” etc., uses original text
Translation failure detection Detects Japanese returned as-is in ja_to_en, uses original text

Recording & Pipeline

Feature Description
InputStream continuous recording PortAudio callback for gapless recording
Ring buffer deque(maxlen=...) auto-discards old data on overrun. Maxlen calculated as block count (v6.4 fix)
Non-blocking pipeline Separate recording thread and API worker thread
HTTP session reuse TCP/TLS handshake only once. Saves 100-300ms per cycle
Atomic write Temp file -> os.replace() prevents OBS read corruption
API retry Both Whisper and translation API retry up to 2 times
Guardrails handling Detects AI Gateway Guardrails blocks (code 2016/2017), skips
429 graceful shutdown Detects Neuron limit reached (429), shuts down safely without infinite retries (v6.5 fix)

Modes & Settings

Feature Description
Microphone mode Picks up your voice. Dynamic noise gate enabled
Stream mode Picks up game/stream audio. Higher VAD threshold
Bidirectional auto-detect Auto-detects Japanese/English, decides translation direction. [JA]/[EN]/[JA?] tags
English-only mode Picks up English only, passes through Japanese
Non-Japanese all mode Picks up all non-Japanese audio, translates to Japanese
Latency modes Choose 3s (low) / 5s (normal) / 8s (accuracy)
Genre hints Game/chat/tech/music/kappa vocabulary hints for Whisper
Translation genre hint Injected into Llama system prompt to reduce literal translation (v6.4)
Whisper model selection Choose standard or high-accuracy model at startup (v6.2+)
15s auto-clear Auto-clears subtitle after 15 seconds of silence
Environment variable API token via CF_API_TOKEN environment variable

Requirements

  • Python 3.10+
  • pip packages: sounddevice, requests, numpy, scipy
  • Cloudflare account (Free tier OK)
  • OBS Studio (Text Source (GDI+) required)

pip install

pip install sounddevice requests numpy scipy

scipy is optional but recommended for higher-quality resampling.


Cloudflare Account Setup

Step 1: Create a Cloudflare Account

  1. Sign up at Cloudflare
  2. Log in to the Cloudflare Dashboard

Step 2: Get Your Account ID

  1. Select your account in the dashboard sidebar
  2. Copy the Account ID (32-character alphanumeric)
  3. Set it in the script as ACCOUNT_ID

Step 3: Create an API Token

  1. Go to API Tokens
  2. Click Create Token
  3. Select Create Custom Token
  4. Set the following permissions:
    • Account > Workers AIRead
    • Account > AI GatewayRead, Edit
  5. Continue to summary -> Create Token
  6. Copy the token (shown only once)

Step 4: Create an AI Gateway

  1. Go to AI Gateway
  2. Click Create Gateway
  3. Enter a name (e.g., default)
  4. Click Create

Auto-creation: Specifying default as the Gateway ID in API requests will auto-create the gateway on first request.

Guardrails: ON or OFF?

Audience Guardrails NG word list Reason
English speakers ON (recommended) Not needed Cloudflare’s native content moderation is high-accuracy for English. Simplest setup.
Japanese speakers OFF (recommended) Custom 200+ words Neuron savings. Japanese NG expressions covered by custom filter.

English speakers: Turn Guardrails ON in the AI Gateway dashboard. Cloudflare will handle content moderation natively.

Japanese speakers: Keep Guardrails OFF. The script includes a 200+ word custom NG filter optimized for Japanese content.

Step 5: Enable AI Gateway Cache (Required – no Neuron savings without it)

  1. Go to AI Gateway and select your gateway
  2. Open Settings
  3. Turn Cache Responses ON
  4. Set default cache TTL to 300 seconds (5 minutes)

Without this ON, caching won’t work. The cf-aig-cache-ttl header alone has no effect. You must enable “Cache Responses” in the dashboard first.

AI Gateway is completely free. Cache and logging features are free with no additional charges.

The script also specifies cache TTL via the cf-aig-cache-ttl header (TRANSLATE_CACHE_TTL = 300) and a custom cache key via cf-aig-cache-key header (uses only the translation direction + source text, so identical phrases get cache hits regardless of prompt formatting).

v6.4 Cache Key Security: v6.3 used f"{direction}:{text}" directly as the cache key, putting Japanese text into the HTTP header. v6.4+ now uses SHA-256 hash (64-char ASCII) for safety while preserving cache identity.

Cache log: The script logs [Cache MISS] and [Cache Hit] so you can verify caching is working.

Step 6: Set Credentials in the Script

Using environment variables (recommended):

# Windows (Command Prompt)
set CF_API_TOKEN=your_token

# Windows (PowerShell)
$env:CF_API_TOKEN = "your_token"

# Mac / Linux
export CF_API_TOKEN=your_token

Or write directly into the script:

CLOUDFLARE_API_TOKEN = os.environ.get("CF_API_TOKEN", "cfat_paste_your_token_here")

Also set ACCOUNT_ID and GATEWAY_ID:

ACCOUNT_ID = "your_account_id"
GATEWAY_ID = "default"  # Gateway name you created

Step 7: Verify Workers AI Access

  1. Go to Workers AI
  2. Confirm the model list is displayed
  3. Check Usage tab for Neuron consumption

Pricing (Don’t Worry)

Item Cost
AI Gateway creation & usage Free
AI Gateway cache feature Free
AI Gateway logging Free
Additional subscription Not required

Workers AI (Whisper + LLM translation) pricing:

Plan Free tier Over limit Auto-billing
Free (current) 10,000 Neurons/day free Errors and stops No
Paid ($5/mo) 10,000 Neurons/day free $0.011 / 1,000 Neurons Yes

You can use the Free plan. Up to 10,000 Neurons per day is free. No auto-billing on overage. It just errors and stops. Billing requires intentionally upgrading to Workers Paid ($5/mo).


Running the Script

python obs_subtitle_translator_0810_v6_5_en.py

At startup, you’ll be prompted to select:

  1. Mode: Microphone (1) or Stream (2)
  2. Language: Translation direction (1-5)
  3. Device: Default (d) or list (l) or device number
  4. Genre: Game/chat/tech/music/none/kappa (1-6)
  5. Latency: Low (3s) / Normal (5s) / Accuracy (8s)
  6. Whisper model: Standard (1) or High-accuracy (2)

Device Number Warning: The default device numbers (DEFAULT_MIC_DEVICE = 7, DEFAULT_GAME_DEVICE = 61) are specific to the author’s machine. Your device numbers will be different. Always enter l at the device selection prompt to list available devices and pick the correct one for your system.


OBS Configuration

  1. Open OBS Studio
  2. Sources -> + -> Text (GDI+)
  3. Open the text source properties
  4. Check Read from file
  5. Browse and select output_mic.txt or output_game.txt
  6. Set Encoding to UTF-8
  7. Adjust font, size, and color

Subtitles update automatically. After 15 seconds of silence, the subtitle is cleared.

Mic Mode Usage Notes

  • Stay silent for the first ~30 seconds after startup (noise floor learning in progress)
  • Do not touch the mic during learning (noise floor will spike)
  • Once [Noise Gate Confirmed] log appears, learning is done – OK to speak
  • Learning with the same environment as streaming (with BGM) is recommended
  • Press Ctrl+C to exit (output file will be cleared)

Use Cases

Example 1: Japanese Streamer -> English Subtitles

Mode: 1 (Microphone)  Language: 1 (Japanese to English)  Latency: 2 (Normal 5s)

Example 2: English Game Stream -> Japanese Subtitles

Mode: 2 (Stream)  Language: 1 (English to Japanese)  Latency: 3 (Accuracy 8s)

Example 3: Bidirectional Auto-Detect (Mixed JP/EN Stream)

Mode: 1 (Microphone)  Language: 3 (Auto-detect)  Latency: 2 (Normal 5s)

Example 4: English-Only Mode (Japanese Pass-Through)

Mode: 2 (Stream)  Language: 4 (English only, Japanese pass-through)

Example 5: Kappa Streaming (Vocabulary Hint)

“Kappa streaming” is a Japanese VTuber/streamer style where the streamer uses sentences ending with “-ppa” (a verbal tic). Genre 6 adds these patterns as Whisper vocabulary hints for better recognition.

Mode: 1 (Microphone)  Language: 1 (Japanese to English)  Genre: 6 (Kappa)

Example 6: Tech Streaming (Technical Terms)

Mode: 1 (Microphone)  Language: 1 (Japanese to English)  Genre: 3 (Tech/Programming)

Example 7: Low Latency Mode

Mode: 1 (Microphone)  Language: 1 (Japanese to English)  Latency: 1 (Low 3s)

Example 8: Accuracy Priority for Noisy Environments

Mode: 2 (Stream)  Language: 1 (English to Japanese)  Latency: 3 (Accuracy 8s)

Example 9: High-Accuracy Whisper Model

Mode: 1 (Microphone)  Language: 1 (Japanese to English)  Whisper model: 2 (High-accuracy)

Whisper Model Selection & Neuron Consumption

Model Comparison

Model Neurons/min Accuracy Temperature=0.0 Hallucination Rate
Standard (@cf/openai/whisper) 41.14 Medium Supported Low
High-accuracy (whisper-large-v3-turbo) 46.63 High Not supported Higher

The high-accuracy model does not support temperature/prompt parameters and sends audio as base64 JSON. Without temperature=0.0 (deterministic output), the high-accuracy model may produce more hallucinations.

Neuron Consumption Breakdown

Based on real-world testing (44 minutes of game streaming, 8-second chunks, auto-detect mode):

Component Neurons/44min % of Total
Whisper (speech recognition) ~1,587 93%
Translation (LLM) ~113 7%
Total ~1,700 100%

Key insight: Whisper accounts for 93% of Neuron consumption. Translation is only 7%. Reducing translation cost (via caching) saves at most 3-5% overall. The most effective way to extend runtime is to reduce Whisper calls (via VAD filtering).

Estimated Runtime (10,000 Neurons/day free tier)

Scenario Model Neurons/min Estimated Runtime
Game streaming (talking constantly) Standard ~38 ~4.4 hours
Game streaming (talking constantly) High-accuracy ~43 ~3.9 hours
Chat streaming (conversation gaps) Standard ~25 ~6.6 hours
Mic mode (quiet, VAD filters 50-70%) Standard ~13 ~13 hours

VAD rejection rate: Game streaming ~13% (always audio), Mic mode ~50-70% (silence filtered). Higher VAD rejection = fewer Whisper calls = longer runtime.

Cache Effectiveness

Cache Type What It Does Neuron Savings
AI Gateway cache (cf-aig-cache-ttl) Caches identical translation requests ~3-5% overall (translation only)
Prompt Caching (x-session-affinity) Caches common prompt prefix ~1-2% overall
Custom cache key (cf-aig-cache-key) Uses only source text as key (v6.3) Higher hit rate for similar phrases
SHA-256 cache key (v6.4) Hashes source text for safe header usage Same hit rate, improved safety

Important: For AI Gateway cache to work, you must enable “Cache Responses” in the AI Gateway dashboard settings.


Troubleshooting

Symptom Cause Fix
Not picking up voice VAD precheck threshold too high Lower VAD_PRECHECK_THRESHOLD from 3.0 to 2.0
Picking up too much noise VAD precheck threshold too low Raise VAD_PRECHECK_THRESHOLD from 3.0 to 5.0
Not picking up game audio VAD threshold too high Lower VAD_THRESHOLD_GAME from 400 to 300
Picking up too much game audio VAD threshold too low Raise VAD_THRESHOLD_GAME from 400 to 500
API error 401 Token permissions insufficient Verify Workers AI Read + AI Gateway Read/Edit permissions
API timeout Network latency Raise API_TIMEOUT from 30 to 60
Subtitle garbled OBS encoding Set encoding to UTF-8 in Text Source (GDI+)
Nothing picked up at startup Noise learning in progress (normal) Wait 30 seconds. OK to speak after [Noise Gate Confirmed]
No [Cache Hit] shown AI Gateway Cache Responses is OFF Turn ON Cache Responses in dashboard -> TTL 300s
scipy error scipy not installed pip install scipy (works without it but with lower accuracy)
[Neuron limit reached] and stops 10,000 Neurons/day free tier exhausted Wait until next day, or upgrade to Workers Paid ($5/mo)

Feature List

  • Whisper speech recognition (standard / high-accuracy / English-only auto-select)
  • LLM translation (llama-3.1-8b-instruct-fast)
  • Dynamic noise gate (mic mode)
  • Frequency VAD (with pre-FFT check)
  • Hallucination detection (Repetition/Short text [ja mode only]/Prompt leak – language-specific filters removed for multilingual support)
  • NG word filter (word boundary support)
  • Translation input NG filter bypass (display filtered, raw text to translation for context preservation)
  • Translation genre hint (Llama system prompt injection, reduces literal translation)
  • Duplicate skip / Translation loop detection / Translation safety refusal detection
  • 15-second auto-clear
  • AI Gateway cache (TTL 300 seconds, custom cache key via cf-aig-cache-key, SHA-256 hashed since v6.4)
  • Prompt Caching (x-session-affinity)
  • Token usage display (Neuron monitoring)
  • Whisper API / Translation API retry (up to 2 times)
  • Auto-detect mode (bidirectional translation, [JA]/[EN]/[JA?] tags)
  • Genre hints (Whisper vocabulary + Llama translation system prompt)

v6.5 Fixes

Fix 1: Prevent NaN in check_vad when voice_mask is empty

Problem: In check_vad(), if voice_mask results in all False (no frequency bins in 200-3400Hz range), np.abs(fft[voice_mask]).mean() returns NaN. Since NaN < vad_threshold evaluates to False, VAD would pass and noise would be sent to Whisper.

Fix: Add np.any(voice_mask) pre-check. If the mask is empty, return False (VAD fail).

Fix 2: Short text filter limited to ja mode only

Problem: The short text skip filter was always active regardless of whisper_language. In English mode, legitimate short English utterances like “Yes”, “OK”, “Hi”, “No” were discarded as hallucinations.

Fix: Only apply the short text filter when whisper_language == "ja".

Fix 3: Handle list-type responses in translate()

Problem: The translate() function had no handling for list type responses. The else block would execute str(response), turning a list into a [...] string representation.

Fix: Add an isinstance(response, list) branch. If the first element is a dict, look for response/text keys; otherwise, treat the element as a string.

Fix 4: Comment removal – README migration

Problem: The v6.4 py file contained ~80 lines of header comments, inflating the file size.

Fix: Removed all comments from the py file, leaving only 4 lines of minimal reference in the header. The removed content has been integrated into this README.

Fix 5: Graceful shutdown on 429 (Neuron limit reached)

Problem: When the 10,000 Neurons/day free tier is exhausted, the API returns 429. Previously, this was retried indefinitely, flooding the console with 429 error messages.

Fix: Added a module-level _quota_exhausted event flag. When 429 is detected, the flag is set and the script shuts down gracefully.


Code Structure

Constants Section (top of file)

Constant Description
CLOUDFLARE_API_TOKEN API token (from CF_API_TOKEN env var)
ACCOUNT_ID / GATEWAY_ID Cloudflare account ID / AI Gateway name
DEFAULT_MIC_DEVICE / DEFAULT_GAME_DEVICE Default device numbers (author-specific – change these)
WHISPER_MODEL_* Whisper model names (standard / English-only / high-accuracy)
TRANSLATE_MODEL Translation LLM model name (llama-3.1-8b-instruct-fast)
TRANSLATE_CACHE_TTL Translation cache TTL (300 seconds)
API_TIMEOUT API timeout (30 seconds)
MAX_LINES / AUTO_HIDE_SEC Max display lines (2) / Auto-clear seconds (15)
VAD_THRESHOLD_MIC / VAD_THRESHOLD_GAME VAD thresholds (mic 100 / stream 400)
VAD_PRECHECK_THRESHOLD Pre-FFT energy check threshold (3.0)
NG_WORDS / NG_WORDS_BOUNDED NG word lists (substring match / word boundary)

Function Reference

Function Description
select_mode() Interactive setup at startup
get_whisper_model() Returns Whisper model based on language
get_headers() Builds API request headers
check_ng_words() NG word filter (mask or skip)
normalize_audio() DC offset removal + peak gain adjustment
trim_silence() Cuts leading/trailing silence
detect_language_simple() Simple language detection
detect_hallucination() Hallucination detection
transcribe() Whisper API speech-to-text (2 retries, guardrails, hallucination filter)
truncate_repeated_translation() Translation output loop detection and trimming
translate() LLM API translation (cache, retry, safety refusal, failure detection)
similarity() Jaccard similarity for duplicate detection
update_output_file() Atomic write to update OBS output file
audio_callback() PortAudio callback (appends audio blocks to ring buffer)
check_vad() Frequency VAD (200-3400Hz, pre-FFT, NaN guard)
capture_one_chunk() Gets one chunk from ring buffer -> process -> WAV
capture_one_chunk_fallback() Fallback when InputStream fails
worker_thread_fn() API worker thread
main() Main function

Pipeline Architecture

[Mic/Stream Audio]
      |
  InputStream (PortAudio callback)  <- continuous gapless recording
      |
  Ring Buffer (deque, maxlen=block count)  <- holds 20 seconds
      |
  capture_one_chunk()  <- noise gate (mic) -> VAD -> normalize -> trim -> resample -> WAV
      |
  Audio Queue (maxsize=5)  <- separates recording thread from API thread
      |
  worker_thread_fn()  <- Whisper API -> hallucination -> NG filter -> translation -> OBS output
      |
  output_mic.txt / output_game.txt  <- atomic write -> OBS Text Source (GDI+)

Version History

v6.5 (0810)

  • Prevent NaN in check_vad when voice_mask is empty (added np.any() pre-check)
  • Short text filter limited to ja mode only (fixes “Yes”, “OK”, “Hi”, “No” being discarded in English mode)
  • Handle list-type responses in translate() (extracts translation from first list element)
  • Graceful shutdown on 429 (Neuron limit reached) (prevents infinite retries, safe shutdown)
  • Comment removal – README migration (reduces py file size by ~15%, eliminates documentation duplication)

v6.4 (0809)

  • Cache Key uses SHA-256 hash (fixes Japanese text in HTTP header)
  • Kanji-only text not dropped in auto mode ([JA?] tag, ja_to_en processing)
  • Ring buffer maxlen calculated as block count (fixes memory waste)
  • Token usage extraction made type-safe
  • Translation input NG filter bypass (display text filtered, raw text passed to translation to preserve context)
  • Translation system prompt genre hint injection (reduces literal translation and game term mistranslation)

v6.3 (0805)

  • Language-specific hallucination filters now only active when whisper_language == "ja"
  • Italian hallucination detection added
  • Custom cache key (cf-aig-cache-key) added
  • [Cache MISS] log added alongside [Cache Hit]
  • Neuron consumption breakdown and estimated runtime table added to README

v6.2 (0805)

  • Translation API Prompt Caching (x-session-affinity) added
  • VAD_PRECHECK_THRESHOLD adjusted 50.0 -> 3.0 (hallucination reduction)
  • VAD_THRESHOLD_MIC adjusted 50 -> 100 (faint noise rejection)
  • Kappa streaming prompt enhanced
  • Whisper model selection added (standard / high-accuracy)
  • whisper-large-v3-turbo support (base64 JSON format)
  • Translation API token usage display added

v6.1 (0802)

  • Pre-FFT energy check (CPU load reduction)
  • Auto-select English Whisper model
  • Translation API AI Gateway cache
  • Pre-computed frequency mask
  • Shortened VAD FFT window

v6.0

  • InputStream + ring buffer (continuous recording)
  • Non-blocking pipeline
  • Pre-compiled NG word regex
  • Translation API retry / Atomic write / Environment variable support
  • HTTP session reuse / Latency mode selection
  • Guardrails error handling
  • Dynamic noise gate learning frame count

License

AI Model Licenses (as of 2026/08/10)

Model Provider License Commercial Use
@cf/openai/whisper OpenAI MIT License Allowed
@cf/openai/whisper-tiny-en OpenAI MIT License Allowed
@cf/openai/whisper-large-v3-turbo OpenAI MIT License Allowed
@cf/meta/llama-3.1-8b-instruct-fast Meta Llama Community License Allowed (< 700M MAU)

Note: If you switch to different models (partner models, etc.), please check their respective terms of use and licenses.

Script License

Released under the MIT License. Feel free to use, modify, and distribute.

MIT License

Copyright (c) 2026

Permission is hereby granted, free of charge, to any person obtaining a copy
of this software and associated documentation files (the "Software"), to deal
in the Software without restriction, including without limitation the rights
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
copies of the Software, and to permit persons to whom the Software is
furnished to do so, subject to the following conditions:

The above copyright notice and this permission notice shall be included in all
copies or substantial portions of the Software.

THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
SOFTWARE.

Disclaimer

  • This script is provided “AS IS”, without any warranty
  • Runs on the Cloudflare Workers AI free tier (10,000 Neurons/day), but may hit the limit depending on usage
  • No auto-billing on overage (it just errors and stops)
  • Billing requires intentionally upgrading to Workers Paid ($5/mo)
  • AI speech recognition and translation are not perfect; misrecognition may occur
  • The author is not responsible for any damages arising from use during streaming
  • Cloudflare service specifications, pricing, and terms of use may change. Check the Cloudflare documentation for the latest information
  • AI model license conditions may change. If you modify this script to use different models, be sure to check the applicable model licenses

Differences from the Japanese Version

The English version is functionally identical to the Japanese version except for the following changes:

Removed Features

Feature Japanese Version English Version Reason
Hangul detection Detects Korean characters, skips Removed English-version users may want to transcribe Korean streams
Cyrillic detection Detects Russian etc., skips Removed English-version users may want to transcribe Russian streams
Greek detection Detects Greek, skips Removed English-version users may want to transcribe Greek streams
Thai detection Detects Thai, skips Removed English-version users may want to transcribe Thai streams
Chinese detection Detects simplified Chinese, skips Removed English-version users may want to transcribe Chinese streams
Special Latin detection Detects Turkish characters, skips Removed English-version users may want to transcribe Turkish streams
Nordic detection Detects Nordic characters, skips Removed English-version users may want to transcribe Nordic language streams
European language detection Detects German/French/Swedish/Dutch/Spanish, skips Removed English-version users may want to transcribe European language streams
Kanji-only detection Detects kanji-only text (<5 chars), skips Removed English-version users may want to transcribe kanji-only text

Kept Features

Feature Status Reason
Short text skip Kept (ja mode only) Only applies when whisper_language == "ja" (v6.5 fix)
Repetition detection Kept Not language-specific
Prompt leak detection Kept Not language-specific
English hallucination skip (ja mode) Kept Only applies when whisper_language == "ja"
Translation failure detection (ja_to_en) Kept Only applies when direction == "ja_to_en"
NG word filter Kept All 200+ NG words kept

Why These Changes Were Made

The Japanese version was built for a Japanese-speaking streamer who primarily speaks Japanese. In this context, Whisper sometimes produces hallucinations in Korean, Chinese, German, French, etc. The language-specific filters were added to catch and discard these hallucinations.

However, the English version targets international users who may speak any language:

  • A French streamer wanting English subtitles would have their French speech incorrectly discarded by the European language filter
  • A Korean streamer wanting English subtitles would have their Korean speech incorrectly discarded by the Hangul filter
  • A Russian streamer wanting English subtitles would have their Russian speech incorrectly discarded by the Cyrillic filter

Removing these filters ensures that valid speech in any language is never incorrectly discarded.

The NG word filter is kept because:

  1. It only masks words (replaces with ***), it doesn’t discard the entire transcription
  2. English speakers using Guardrails ON (recommended) will have Cloudflare’s native moderation handle this
  3. Japanese speakers using Guardrails OFF still benefit from the 200+ Japanese NG words
  4. Users can customize NG_WORDS and NG_WORDS_BOUNDED in the script for their own language

v6.5 Short Text Filter Change

In v6.5, the short text filter was limited to whisper_language == "ja" only. This means:

  • Japanese version (ja mode): Short text filter is active – same behavior as before
  • English version (en/auto mode): Short text filter is effectively disabled – short English utterances like “Yes”, “OK”, “Hi”, “No” are no longer discarded

Summary

The Japanese version is optimized for Japanese streamers who need to filter out hallucinations in other languages. The English version is designed for international users who may transcribe and translate any language, so language-specific hallucination filters are removed to avoid dropping valid transcriptions.


References


Enjoy Use It :DV6.5

コメント