> ## Documentation Index
> Fetch the complete documentation index at: https://docs.cartesia.ai/llms.txt
> Use this file to discover all available pages before exploring further.

# ターン検出を使用した OpenAI Realtime Transcription からの移行

このガイドでは、`turn_detection: server_vad` と併用する OpenAI Realtime Transcription からの移行について説明します。

<Card horizontal title="すべての移行ガイド" icon="arrow-left-from-arc" href="/ja-jp/use-the-api/stt/migrations" />

このガイドには、素の API の説明と SDK コードの両方が含まれています。SDK をインストールするには次のようにします。

<CodeGroup>
  ```bash Python theme={null}
  pip install cartesia
  ```

  ```bash TypeScript theme={null}
  npm i @cartesia/cartesia-js
  ```
</CodeGroup>

<Info>
  すでに Cartesia SDK を使用している場合は、バージョン `>=3.2.0` にアップグレードしてください
</Info>

<Note>
  Ink 2 は現時点で英語のみをサポートしています。\
  今後数ヶ月のうちに他言語の追加を予定しています。
</Note>

## 接続

OpenAI の WebSocket URL と認証ヘッダーを Cartesia の `/stt/turns/websocket` に置き換え、使用したいモデルと入力音声フォーマットをクエリパラメーターとして指定します。

```diff theme={null}
- wss://api.openai.com/v1/realtime?intent=transcription
+ wss://api.cartesia.ai/stt/turns/websocket?model=ink-2&encoding=pcm_s16le&sample_rate=24000
```

```diff theme={null}
- Authorization: Bearer <OPENAI_API_KEY>
+ Authorization: Bearer <CARTESIA_API_KEY>
+ Cartesia-Version: 2026-03-01
```

ブラウザでは、WebSocket はリクエストヘッダーをサポートしていません。代わりに、API バージョンを `cartesia_version` クエリパラメーターとして渡し、API キーの代わりに `access_token` クエリパラメーターで有効期限の短い[アクセストークン](/get-started/authenticate-your-client-applications)を使用してください。

Cartesia SDK を使用して自動ファイナライズ WebSocket に接続します。

<CodeGroup>
  ```python Python (Async) theme={null}
  import os
  from cartesia import AsyncCartesia

  client = AsyncCartesia(api_key=os.getenv("CARTESIA_API_KEY"))

  async with client.stt.auto_finalize.websocket(
      model="ink-2", encoding="pcm_s16le", sample_rate=24000
  ) as connection:
      ...
  ```

  ```python Python theme={null}
  import os
  from cartesia import Cartesia

  client = Cartesia(api_key=os.getenv("CARTESIA_API_KEY"))

  with client.stt.auto_finalize.websocket(
      model="ink-2", encoding="pcm_s16le", sample_rate=24000
  ) as connection:
      ...
  ```

  ```typescript TypeScript theme={null}
  import Cartesia from "@cartesia/cartesia-js";

  const client = new Cartesia({ apiKey: process.env.CARTESIA_API_KEY });

  const connection = client.stt.autoFinalize.websocket({
    model: "ink-2",
    encoding: "pcm_s16le",
    sample_rate: 24000,
  });
  ```

  ```typescript TypeScript (Browser) theme={null}
  // Server-side: Generate access-tokens using your API key
  import Cartesia from '@cartesia/cartesia-js';

  const client = new Cartesia({ apiKey: process.env.CARTESIA_API_KEY });

  export async function GET() {
    const { token } = await client.accessToken.create({
      grants: { stt: true, tts: false, agent: false },
      // How long the token lasts in seconds
      // Allowed values: 0–3600
      expires_in: 3600,
    });
    return Response.json({ token });
  }


  // Client-side
  // 1. Fetch an access token from your server
  // 2. Connect to Cartesia via WebSocket
  import Cartesia from "@cartesia/cartesia-js";

  async function getToken(): Promise<string> {
    const res = await fetch('/replace-with-your-server');
    const { token } = await res.json();
    return token;
  }
  const audioContext = new AudioContext();

  const client = new Cartesia({ token: await getToken() });

  const connection = client.stt.autoFinalize.websocket({
    model: "ink-2",
    encoding: "pcm_f32le",
    sample_rate: audioContext.sampleRate,
  });
  ```
</CodeGroup>

## セッション設定

OpenAI は `session.update` ペイロードでセッションを設定します。Cartesia は同等の設定をクエリパラメーターとして受け取ります。

| OpenAI のセッション設定                                        | Cartesia Realtime STT (Auto)                                                             | 備考                                                                                                     |
| ------------------------------------------------------ | ---------------------------------------------------------------------------------------- | ------------------------------------------------------------------------------------------------------ |
| `?intent=transcription`                                | —                                                                                        | Ink は文字起こしのみをサポートします。                                                                                  |
| `audio.input.transcription.model`（`gpt-4o-transcribe`） | `model=ink-2` <Badge color="red" size="sm">required</Badge>                              | すべてのオプションは[モデル](/build-with-cartesia/stt/latest)を参照してください。                                             |
| `audio.input.format`（`audio/pcm`、24 kHz）               | `encoding=pcm_s16le` + `sample_rate=24000` <Badge color="red" size="sm">required</Badge> | Cartesia はさらに多くの入力音声フォーマットをサポートしています。すべてのオプションは[エンコーディング](#encoding)を参照してください。                         |
| `audio.input.turn_detection`（`server_vad`）             | —                                                                                        | ターン検出を無効にするには[手動ファイナライズ](/use-the-api/stt/migrate-from-openai-realtime-transcription/manual)を参照してください。 |
| `audio.input.transcription.language`                   | —                                                                                        | `ink-2` は現在 `en` のみをサポートしています。今後さらに多くの言語に対応予定です！                                                       |
| `audio.input.transcription.delay`                      | —                                                                                        | 設定できません。                                                                                               |
| `audio.input.noise_reduction`                          | —                                                                                        | 不要です。                                                                                                  |
| —                                                      | `cartesia_version=2026-03-01` <Badge color="red" size="sm">required</Badge>              | 詳細は [API 規約](/use-the-api/api-conventions#always-send-a-cartesia-version-header)を参照してください。             |

<Accordion title="encoding">
  OpenAI は入力形式を `audio.input.format` で設定します。Cartesia は `encoding` と `sample_rate` をクエリパラメーターとして受け取ります。

  | OpenAI `audio.input.format`              | Cartesia `encoding` | Cartesia `sample_rate` |
  | ---------------------------------------- | ------------------- | ---------------------- |
  | `{ "type": "audio/pcm", "rate": 24000 }` | `pcm_s16le`         | `24000`                |
  | `g711_ulaw`                              | `pcm_mulaw`         | `8000`                 |
  | `g711_alaw`                              | `pcm_alaw`          | `8000`                 |

  OpenAI の PCM 形式は 16 ビット、24 kHz、モノラルです。Cartesia はその `sample_rate` をそのまま受け付けるため、リサンプリングせずに同じ音声をストリーミングできます。Cartesia は `pcm_s32le`、`pcm_f16le`、`pcm_f32le` も受け付けます。
</Accordion>

## 音声の送信

OpenAI は各音声チャンクを JSON 形式のテキストフレームでラップし、音声バイトを base64 エンコードします。\
Cartesia は音声チャンクをバイナリフレームとして受け取ります。生の音声バイトを直接送信してください。

```diff theme={null}
- { "type": "input_audio_buffer.append", "audio": "<base64 PCM>" }
+ <raw PCM bytes>
```

OpenAI の `session.update` メッセージに相当するものはありません。パラメーターを変更するには、新しい WebSocket に再接続してください。

すべての音声をコミットしてセッションを閉じるには、JSON 形式のテキストフレームを送信します。

```json theme={null}
{ "type": "close" }
```

Cartesia はバッファーされたすべての音声を文字起こしし、その後ソケットを閉じます。

<Warning>
  現在 OpenAI で `input_audio_buffer.commit` を使用してセッションの途中で音声をコミットしている場合は、代わりに Cartesia の[手動ファイナライズ](./manual)の使用を検討してください。

  詳細は[移行ガイド](/use-the-api/stt/migrations)のページを参照してください。
</Warning>

### SDK を使用した音声の送信

<CodeGroup>
  ```python Python (Async) theme={null}
  # raw_audio (bytes) - Raw audio data, about 100 ms at a time
  await connection.send_raw(raw_audio)
  ```

  ```python Python theme={null}
  # raw_audio (bytes) - Raw audio data, about 100 ms at a time
  connection.send_raw(raw_audio)
  ```

  ```typescript TypeScript theme={null}
  // @param {ArrayBufferLike} rawAudio - raw audio data, about 100 ms at a time
  connection.sendRaw(rawAudio);
  ```
</CodeGroup>

### 送信前に base64 エンコードされた音声をデコードする

<CodeGroup>
  ```python Python (Async) theme={null}
  from base64 import b64decode

  await connection.send_raw(b64decode(audio_base_64))
  ```

  ```python Python theme={null}
  from base64 import b64decode

  connection.send_raw(b64decode(audio_base_64))
  ```

  ```typescript TypeScript theme={null}
  connection.sendRaw(Uint8Array.fromBase64(audioBase64));
  ```
</CodeGroup>

### 終了

<CodeGroup>
  ```python Python (Async) theme={null}
  # Commit buffered audio
  # and let the server close the socket once done
  await connection.send({"type": "close"})

  # Close the socket early (optional)
  connection.close()
  ```

  ```python Python theme={null}
  # Commit buffered audio
  # and let the server close the socket once done
  connection.send({"type": "close"})

  # Close the socket early (optional)
  connection.close()
  ```

  ```typescript TypeScript theme={null}
  // Commit buffered audio
  // and let the server close the socket once done
  connection.send({ type: "close" });

  // Close the socket early (optional)
  connection.close()
  ```
</CodeGroup>

## イベントのマッピング

OpenAI は `input_audio_buffer.speech_started` / `speech_stopped` / `committed` でターンを通知し、その後ターンごとにトランスクリプトのデルタと `completed` イベントを一気に送信します。

Cartesia は同じ情報をターンのライフサイクルにまとめます。`turn.start`、`turn.update`、`turn.eager_end`、`turn.resume`、`turn.end` です。完全なステートマシンについては[ターン検出](/use-the-api/stt/turns)を参照してください。

| OpenAI `type`                                           | Cartesia `type`  | 備考                                                                             |
| ------------------------------------------------------- | ---------------- | ------------------------------------------------------------------------------ |
| `session.created` / `session.updated`                   | `connected`      | Cartesia にはセッション設定のラウンドトリップがありません。音声を送信する前に待機する必要はありません。                       |
| `input_audio_buffer.speech_started`                     | `turn.start`     | ユーザーが話し始めました。トランスクリプトは含みません。                                                   |
| `conversation.item.input_audio_transcription.delta`     | `turn.update`    | OpenAI はターンのコミット後にデルタを一気に送信しますが、Cartesia の `turn.update` はターン**中**にストリーミングします。 |
| `input_audio_buffer.speech_stopped` / `committed`       | `turn.end`       | ユーザーが話し終え、ターンがコミットされました。                                                       |
| `conversation.item.input_audio_transcription.completed` | `turn.end`       | ターンの確定トランスクリプト。                                                                |
| —                                                       | `turn.eager_end` | モデルはユーザーが話し終えた可能性を予測します。無視しても構いません。                                            |
| —                                                       | `turn.resume`    | ユーザーが話し続けたため、直前の `turn.eager_end` を無視します。                                      |
| `error`                                                 | `error`          | クライアントまたはサーバーのエラー。                                                             |

### 確定したトランスクリプト

OpenAI の `conversation.item.input_audio_transcription.completed` イベント:

```json theme={null}
{
  "type": "conversation.item.input_audio_transcription.completed",
  "item_id": "item_003",
  "content_index": 0,
  "transcript": "Hello world!"
}
```

は、Cartesia の `turn.end` イベントになります:

```json theme={null}
{
  "type": "turn.end",
  "transcript": "Hello world!",
  "request_id": "33cacee6-1936-4949-a05b-ecc9f2393248"
}
```

<Note>`turn.start` と `turn.resume` イベントはトランスクリプトを含みません。</Note>

<CodeGroup>
  ```python Python (Async) theme={null}
  import asyncio
  from cartesia.types.stt import STTAutoFinalizeWebsocketResponse

  full_transcript = ""

  async def receive() -> None:
      global full_transcript
      async for event in connection:
          if event.type == "turn.start":
              print("speech_started")
          elif event.type == "turn.update":
              # cumulative within a turn
              print(f"Transcript so far: {event.transcript}")
          elif event.type == "turn.end":
              # Do not strip or add spaces!
              full_transcript += event.transcript
              print(f"speech_stopped: {event.transcript}")
          elif event.type == "error":
              print(f"error: {event.message}")

  # Run receive() concurrently with your audio sender:
  #   await asyncio.gather(send_audio(), receive())
  ```

  ```python Python theme={null}
  from cartesia.types.stt import STTAutoFinalizeWebsocketResponse

  full_transcript = ""

  for event in connection:
      if event.type == "turn.start":
          print("speech_started")
      elif event.type == "turn.update":
          # cumulative within a turn
          print(f"Transcript so far: {event.transcript}")
      elif event.type == "turn.end":
          # Do not strip or add spaces!
          full_transcript += event.transcript
          print(f"speech_stopped: {event.transcript}")
      elif event.type == "error":
          print(f"error: {event.message}")
  ```

  ```typescript TypeScript theme={null}
  import Cartesia from '@cartesia/cartesia-js';

  let fullTranscript = '';

  for await (const event of connection.stream()) {
    if (event.type === 'message') {
      const m = event.message;
      switch (m.type) {
        case 'turn.start':
          console.log('speech_started');
          break;
        case 'turn.update':
          // cumulative within a turn
          console.log(`Transcript so far: ${m.transcript}`);
          break;
        case 'turn.end':
          // Do not trim or add spaces!
          fullTranscript += m.transcript;
          console.log(`speech_stopped: ${m.transcript}`);
          break;
      }
    } else if (event.type === 'error') {
      console.error(`error: ${event.error.message}`);
    }
  }
  ```
</CodeGroup>

## サーバーメッセージの例

> OpenAI はターンごとにバッチ処理します。Ink はターン中にストリーミングします。

| OpenAI gpt-4o-transcribe (server VAD)                                                               | Cartesia Realtime STT (Auto)                                               |
| --------------------------------------------------------------------------------------------------- | -------------------------------------------------------------------------- |
| <Badge>session.updated</Badge>                                                                      | <Badge>connected</Badge>                                                   |
| <Badge>speech\_started</Badge>                                                                      | <Badge>turn.start</Badge>                                                  |
| —                                                                                                   | <Badge color="orange">turn.update</Badge> `"OpenAI batches"`               |
| —                                                                                                   | <Badge color="orange">turn.update</Badge> `"OpenAI batches each turn."`    |
| —                                                                                                   | <Badge>turn.eager\_end</Badge> `"OpenAI batches each turn."`               |
| <Badge>speech\_stopped</Badge> + <Badge>committed</Badge>                                           | —                                                                          |
| <Badge color="orange">…transcription.delta</Badge> `"OpenAI batches each turn."` *(コミット後に一気に送信)*    | —                                                                          |
| <Badge color="green">…transcription.completed</Badge> `"OpenAI batches each turn."`                 | <Badge color="green">turn.end</Badge> `"OpenAI batches each turn."`        |
| <Badge>speech\_started</Badge>                                                                      | <Badge>turn.start</Badge>                                                  |
| —                                                                                                   | <Badge color="orange">turn.update</Badge> `"Ink streams"`                  |
| —                                                                                                   | <Badge>turn.eager\_end</Badge> `"Ink streams"`                             |
| —                                                                                                   | <Badge>turn.resume</Badge>                                                 |
| —                                                                                                   | <Badge color="orange">turn.update</Badge> `"Ink streams within the turn."` |
| —                                                                                                   | <Badge>turn.eager\_end</Badge> `"Ink streams within the turn."`            |
| <Badge>speech\_stopped</Badge> + <Badge>committed</Badge>                                           | —                                                                          |
| <Badge color="orange">…transcription.delta</Badge> `"Ink streams within the turn."` *(コミット後に一気に送信)* | —                                                                          |
| <Badge color="green">…transcription.completed</Badge> `"Ink streams within the turn."`              | <Badge color="green">turn.end</Badge> `"Ink streams within the turn."`     |

## 参考資料

<CardGroup cols={2}>
  <Card icon="code" title="API リファレンス" href="/api-reference/stt/turns/websocket">
    Cartesia Realtime STT (Auto)
  </Card>

  <Card icon="brackets-curly" title="完全なコード例" href="/examples/stt-auto-finalize-websocket">
    Cartesia SDK の使用
  </Card>
</CardGroup>
