メインコンテンツへスキップ

目的

定型フレーズ(挨拶、保留メッセージ、締めの言葉)は通話をまたいで繰り返し使われます。毎回生成し直すとレイテンシが増え、クレジットも消費します。代わりに、これらのフレーズを raw PCM として一度だけ事前生成してキャッシュし、実行時にライブの TTS ストリームへ差し込みます。キャッシュ済みクリップは API を経由しないため、その区間は高速かつ無料になります。

始める前に

以下が必要です:
  • API キーplay.cartesia.ai から API キーを取得してください。Cartesia を初めて利用する場合は、リアルタイム TTS クイックスタート を参照してください。
  • Raw コンテナcontainer: "raw"(ヘッダーなし PCM)を設定します。WAV や MP3 などのコンテナはヘッダーが付加されるため連結が壊れます。TTS 出力フォーマット を参照してください。
  • エンコーディングとサンプルレートの一致 — キャッシュ済みクリップはライブストリームと完全に一致している必要があります(例:24000 Hz の pcm_s16le)。
  • モデル、ボイス、言語の一致 — 本番環境では日付付きモデルスナップショット(例:sonic-3.5-2026-05-04)に固定し、キャッシュ済み音声とライブ音声が同一に聞こえるようにします。
キャッシュ済み音声とライブ音声は、クリックや歪みなく連結できるようバイト互換である必要があります。

プロジェクトのセットアップ

このガイドに沿って進めるには、以下のようにして tts-caching という Python の uv プロジェクトを初期化してください:

ステップ 1: フレーズキャッシュを構築する

以下のスクリプトで音声フレーズキャッシュを生成します。このスクリプトは PHRASES の各フレーズを生成し、raw 音声 PCM バイトを phrase-cache ディレクトリに保存します。
build_cache.py
一度だけ実行します:

ステップ 2: 実行時にインターリーブする

実行時に、キャッシュ済みフレーズとライブフレーズのシーケンスを 1 つの出力バッファへと処理します。
interleave_tts.py
実行します:
spliced.wav を試聴してください。キャッシュ済みフレーズがライブ生成された音声とシームレスに繋がります。

設計パターン

interleave_tts.py では、シーケンス全体を通じて WebSocket を開いたままにしています。「ライブ」フレーズだけが Cartesia TTS を呼び出します。キャッシュ済みフレーズはストア(ディスク、S3、任意の場所)から取得するため、クレジットを消費するのはライブ部分だけです。

注意事項

  • 音声フォーマットの不一致: キャッシュ済みクリップがライブ音声と異なるエンコーディングやサンプルレートを使っていると、接合部でクリック音や歪みが聞こえます。
  • モデルを固定する: 同じボイス ID でも、異なる TTS モデルバージョンを使うと音声生成に影響が出ることがあります。日付付きスナップショット(例:sonic-3.5-2026-05-04)に固定して、キャッシュ済み音声とライブ音声を同期させてください。
  • 5 分のアイドルタイムアウト: TTS WebSocket は 5 分間アクティビティがないと切断されます。キャッシュ済みクリップを再生するだけの目的で切断しないでください。再接続コストが増えるだけです。ライブ生成の間隔が長い場合は、接続をアイドル状態で保持するのではなく、いったんクローズして再度オープンしてください。
  • 完全なフレーズはきれいに繋がる: Sonic TTS は前後の単語を感情や口調のコンテキストとして利用します。TTS クリップは完全な文として始まり、完全な文で終わるようにしてください。
  • WebSocket パターン: このガイドでは TTS WebSocket を使用しており、複数回の生成にわたって 1 つの接続を開いたままにします。Bytes および SSE エンドポイントは生成ごとに 1 リクエストで動作するため、インターリーブする対象となる開いた接続がありません。TTS エンドポイントの種類 を参照してください。