> This is a page from the ElevenLabs documentation. For a complete page index, fetch https://elevenlabs.io/docs/llms.txt. For the full documentation in a single file, fetch https://elevenlabs.io/docs/llms-full.txt.

# Streaming no servidor

> **Note**
>
> **Guia prático** · Pressupõe que você concluiu o [guia de início rápido de Speech to Text ](/docs/pt/eleven-api/guides/cookbooks/speech-to-text).

## Visão geral

A API de Speech to Text em Tempo Real da ElevenLabs permite transcrever streams de áudio em tempo real com latência ultrabaixa usando o modelo Scribe Realtime v2. Seja para criar assistentes de voz, serviços de transcrição ou qualquer aplicação que exija reconhecimento de fala ao vivo, esta API baseada em WebSocket fornece transcrições parciais enquanto você fala e transcrições confirmadas quando os segmentos de fala são concluídos.

O Scribe v2 Realtime pode ser implementado no servidor para transcrever áudio em tempo real, seja por uma URL, arquivo ou seu próprio stream de áudio.

A implementação no servidor difere da implementação no cliente em alguns pontos:

* Usa uma chave de API da ElevenLabs em vez de um token de uso único.
* Compatível com streaming diretamente de uma URL, sem a necessidade de dividir manualmente o áudio em partes.

Para fazer streaming de áudio diretamente do microfone, consulte o guia de [streaming no cliente](/docs/pt/eleven-api/guides/how-to/speech-to-text/realtime/client-side-streaming).

## Início rápido

> **Note**
>
> Este guia pressupõe que você [configurou sua chave de API e o SDK](/docs/pt/eleven-api/quickstart). Conclua
> primeiro o início rápido, caso ainda não tenha feito isso.

#### Configure o SDK

O SDK oferece duas formas de transcrever áudio em tempo real: streaming a partir de uma URL ou dividindo manualmente o áudio de um arquivo ou do seu próprio stream de áudio.

> **Info**
>
> Para ver a lista completa de parâmetros e opções compatíveis com a API, consulte a [referência da API](/docs/pt/api-reference/speech-to-text/v-1-speech-to-text-realtime).

#### Streaming a partir de uma URL

Este exemplo mostra como fazer streaming de um arquivo de áudio a partir de uma URL usando o SDK oficial.

> **Warning**
>
> A ferramenta `ffmpeg` é necessária para fazer streaming a partir de uma URL. Acesse [o site dela](https://ffmpeg.org/download.html) para ver instruções de instalação.

Crie um novo arquivo chamado `example.py` ou `example.mts`, dependendo da linguagem escolhida, e adicione o código a seguir:

```python
from dotenv import load_dotenv
import os
import asyncio
from elevenlabs import ElevenLabs, RealtimeEvents, RealtimeUrlOptions

load_dotenv()

async def main():
    elevenlabs = ElevenLabs(api_key=os.getenv("ELEVENLABS_API_KEY"))

    # Create an event to signal when to stop
    stop_event = asyncio.Event()

    # Connect to a streaming audio URL
    connection = await elevenlabs.speech_to_text.realtime.connect(RealtimeUrlOptions(
        model_id="scribe_v2_realtime",
        url="https://npr-ice.streamguys1.com/live.mp3",
        include_timestamps=True,
    ))

    # Set up event handlers
    def on_session_started(data):
        print(f"Session started: {data}")

    def on_partial_transcript(data):
        print(f"Partial: {data.get('text', '')}")

    def on_committed_transcript(data):
        print(f"Committed: {data.get('text', '')}")

    # Committed transcripts with word-level timestamps. Only received when include_timestamps is set to True.
    def on_committed_transcript_with_timestamps(data):
        print(f"Committed with timestamps: {data.get('words', '')}")

    # Errors - will catch all errors, both server and websocket specific errors
    def on_error(error):
        print(f"Error: {error}")
        # Signal to stop on error
        stop_event.set()

    def on_close():
        print("Connection closed")

    # Register event handlers
    connection.on(RealtimeEvents.SESSION_STARTED, on_session_started)
    connection.on(RealtimeEvents.PARTIAL_TRANSCRIPT, on_partial_transcript)
    connection.on(RealtimeEvents.COMMITTED_TRANSCRIPT, on_committed_transcript)
    connection.on(RealtimeEvents.COMMITTED_TRANSCRIPT_WITH_TIMESTAMPS, on_committed_transcript_with_timestamps)
    connection.on(RealtimeEvents.ERROR, on_error)
    connection.on(RealtimeEvents.CLOSE, on_close)

    print("Transcribing audio stream... (Press Ctrl+C to stop)")

    try:
        # Wait until error occurs or connection closes
        await stop_event.wait()
    except KeyboardInterrupt:
        print("\nStopping transcription...")
    finally:
        await connection.close()

if __name__ == "__main__":
    asyncio.run(main())
```

```typescript
import "dotenv/config";
import { ElevenLabsClient, RealtimeEvents } from "@elevenlabs/elevenlabs-js";

const elevenlabs = new ElevenLabsClient();

const connection = await elevenlabs.speechToText.realtime.connect({
  modelId: "scribe_v2_realtime",
  url: "https://npr-ice.streamguys1.com/live.mp3",
  includeTimestamps: true,
});

connection.on(RealtimeEvents.SESSION_STARTED, (data) => {
  console.log("Session started", data);
});

connection.on(RealtimeEvents.PARTIAL_TRANSCRIPT, (transcript) => {
  console.log("Partial transcript", transcript);
});

connection.on(RealtimeEvents.COMMITTED_TRANSCRIPT, (transcript) => {
  console.log("Committed transcript", transcript);
});

connection.on(RealtimeEvents.COMMITTED_TRANSCRIPT_WITH_TIMESTAMPS, (transcript) => {
  console.log("Committed with timestamps", transcript);
});

connection.on(RealtimeEvents.ERROR, (error) => {
  console.log("Error", error);
});

connection.on(RealtimeEvents.CLOSE, () => {
  console.log("Connection closed");
});

```

#### Divisão manual de áudio em blocos

A maneira mais fácil de transcrever áudio usando o Scribe é utilizar o SDK oficial. Caso não seja possível usar o SDK, você pode usar a API WebSocket diretamente. Veja o exemplo de WebSocket abaixo para saber como usar a API WebSocket.

Este exemplo simula uma transcrição em tempo real de um arquivo de áudio.

```python
import asyncio
import base64
import os
from dotenv import load_dotenv
from pathlib import Path
from elevenlabs import AudioFormat, CommitStrategy, ElevenLabs, RealtimeEvents, RealtimeAudioOptions
from pydub import AudioSegment
import sys

load_dotenv()

async def main():
    # Initialize the ElevenLabs client
    elevenlabs = ElevenLabs(api_key=os.getenv("ELEVENLABS_API_KEY"))

    # Create an event to signal when transcription is complete
    transcription_complete = asyncio.Event()

    # Connect with manual audio chunk mode
    connection = await elevenlabs.speech_to_text.realtime.connect(RealtimeAudioOptions(
        model_id="scribe_v2_realtime",
        audio_format=AudioFormat.PCM_16000,
        sample_rate=16000,
        commit_strategy=CommitStrategy.MANUAL,
        include_timestamps=True,
    ))

    # Set up event handlers
    def on_session_started(data):
        print(f"Session started: {data}")
        # Start sending audio once session is ready
        asyncio.create_task(send_audio())

    def on_partial_transcript(data):
        transcript = data.get('text', '')
        if transcript:
            print(f"Partial: {transcript}")

    def on_committed_transcript(data):
        transcript = data.get('text', '')
        print(f"\nCommitted transcript: {transcript}")

    def on_committed_transcript_with_timestamps(data):
        print(f"Timestamps: {data.get('words', '')}")
        print("-" * 50)
        # Signal that transcription is complete
        transcription_complete.set()

    def on_error(error):
        print(f"Error: {error}")
        transcription_complete.set()

    def on_close():
        print("Connection closed")
        transcription_complete.set()

    # Register event handlers
    connection.on(RealtimeEvents.SESSION_STARTED, on_session_started)
    connection.on(RealtimeEvents.PARTIAL_TRANSCRIPT, on_partial_transcript)
    connection.on(RealtimeEvents.COMMITTED_TRANSCRIPT, on_committed_transcript)
    connection.on(RealtimeEvents.COMMITTED_TRANSCRIPT_WITH_TIMESTAMPS, on_committed_transcript_with_timestamps)
    connection.on(RealtimeEvents.ERROR, on_error)
    connection.on(RealtimeEvents.CLOSE, on_close)

    # Convert audio file to PCM format if necessary
    def load_and_convert_audio(audio_path: str | Path, target_sample_rate: int = 16000) -> bytes:
        try:
            if str(audio_path).lower().endswith('.pcm'):
                with open(audio_path, 'rb') as f:
                    return f.read()

            audio = AudioSegment.from_file(audio_path)
            if audio.channels > 1:
                audio = audio.set_channels(1)
            if audio.frame_rate != target_sample_rate:
                audio = audio.set_frame_rate(target_sample_rate)
            audio = audio.set_sample_width(2)
            return audio.raw_data
        except Exception as e:
            print(f"Error loading audio: {e}")
            sys.exit(1)

    async def send_audio():
        """Send audio chunks from an audio file"""
        audio_file_path = Path("/path/to/audio.mp3")

        try:
            # Read the audio file
            audio_data = load_and_convert_audio(audio_file_path)

            # Split into chunks (1 second of audio = 32000 bytes at 16kHz, 16-bit)
            chunk_size = 32000
            chunks = [audio_data[i:i + chunk_size] for i in range(0, len(audio_data), chunk_size)]

            # Send each chunk
            for i, chunk in enumerate(chunks):
                chunk_base64 = base64.b64encode(chunk).decode('utf-8')
                await connection.send({"audio_base_64": chunk_base64, "sample_rate": 16000})

                # Wait 1 second between chunks (simulating real-time)
                if i < len(chunks) - 1:
                    await asyncio.sleep(1)

            # Small delay before committing to let last chunk process
            await asyncio.sleep(0.5)

            # Commit to finalize segment and get committed transcript
            await connection.commit()

        except Exception as e:
            print(f"Error sending audio: {e}")
            transcription_complete.set()

    try:
        # Wait for transcription to complete
        await transcription_complete.wait()
    except KeyboardInterrupt:
        print("\nStopping...")
    finally:
        await connection.close()

if __name__ == "__main__":
    asyncio.run(main())

```

```typescript
import "dotenv/config";
import * as fs from "node:fs";
import { ElevenLabsClient, RealtimeEvents, AudioFormat } from "@elevenlabs/elevenlabs-js";

const elevenlabs = new ElevenLabsClient();

const connection = await elevenlabs.speechToText.realtime.connect({
  modelId: "scribe_v2_realtime",
  audioFormat: AudioFormat.PCM_16000,
  sampleRate: 16000,
  includeTimestamps: true,
});

connection.on(RealtimeEvents.SESSION_STARTED, (data) => {
  console.log("Session started", data);
  sendAudio();
});

connection.on(RealtimeEvents.PARTIAL_TRANSCRIPT, (transcript) => {
  console.log("Partial transcript", transcript);
});

connection.on(RealtimeEvents.COMMITTED_TRANSCRIPT, (transcript) => {
  console.log("Committed transcript", transcript);
});

connection.on(RealtimeEvents.COMMITTED_TRANSCRIPT_WITH_TIMESTAMPS, (transcript) => {
  console.log("Committed with timestamps", transcript);
});

connection.on(RealtimeEvents.ERROR, (error) => {
  console.log("Error", error);
});

connection.on(RealtimeEvents.CLOSE, () => {
  console.log("Connection closed");
});

async function sendAudio() {
  const pcmFilePath = "/path/to/audio.pcm";

  const chunkSize = 32000; // 1 second of 16kHz audio (16000 samples * 2 bytes per sample)

  // Read the entire file into a buffer
  const audioBuffer = fs.readFileSync(pcmFilePath);

  // Split the buffer into chunks of exactly chunkSize bytes
  const chunks: Buffer[] = [];
  for (let i = 0; i < audioBuffer.length; i += chunkSize) {
    const chunk = audioBuffer.subarray(i, i + chunkSize);
    chunks.push(chunk);
  }

  // Send each chunk via websocket payload
  for (let i = 0; i < chunks.length; i++) {
    const chunk = chunks[i];
    const chunkBase64 = chunk.toString("base64");

    connection.send({
      audioBase64: chunkBase64,
      sampleRate: 16000,
    });

    // Wait 1 second between chunks to simulate real-time streaming
    // (each chunk contains 1 second of audio at 16kHz)
    if (i < chunks.length - 1) {
      await new Promise(resolve => setTimeout(resolve, 1000));
    }
  }

  // Small delay before final commit to let the last chunk process
  await new Promise(resolve => setTimeout(resolve, 500));

  // send final commit
  connection.commit();
}
```

**`Exemplo de WebSocket em Python`**

```python title="Exemplo de WebSocket em Python"
# Use this example if you are unable to use the SDK
import asyncio
import base64
import json
import websockets
from dotenv import load_dotenv
import os

load_dotenv()

async def send_audio(ws, audio_data):
    """Send audio chunks to the websocket"""
    chunk_size = 32000  # 1 second of 16kHz audio

    for i in range(0, len(audio_data), chunk_size):
        chunk = audio_data[i : i + chunk_size]
        await ws.send(
            json.dumps(
                {
                    "message_type": "input_audio_chunk",
                    "audio_base_64": base64.b64encode(chunk).decode(),
                    "commit": False,
                    "sample_rate": 16000,
                }
            )
        )
        # Wait 1 second between chunks to simulate real-time streaming
        await asyncio.sleep(1)

    # Small delay before final commit
    await asyncio.sleep(0.5)

    # Send final commit
    await ws.send(
        json.dumps(
            {
                "message_type": "input_audio_chunk",
                "audio_base_64": "",
                "commit": True,
                "sample_rate": 16000,
            }
        )
    )

async def receive_transcripts(ws):
    """Receive and process transcripts from the websocket"""
    while True:
        try:
            # Wait for 10 seconds for a message
            # Adjust the timeout in cases where audio files have more than 10 seconds before speech starts, or if the audio is longer than 10 seconds.
            message = await asyncio.wait_for(ws.recv(), timeout=10.0)
            data = json.loads(message)

            if data["message_type"] == "partial_transcript":
                print(f"Partial: {data['text']}")
            elif data["message_type"] == "committed_transcript":
                print(f"Committed: {data['text']}")
            elif data["message_type"] == "committed_transcript_with_timestamps":
                print(f"Committed with timestamps: {data['words']}")
                break
            elif data["message_type"] == "input_error":
                print(f"Error: {data}")
        except asyncio.TimeoutError:
            print("Timeout waiting for transcript")


async def transcribe():
    url = "wss://api.elevenlabs.io/v1/speech-to-text/realtime?model_id=scribe_v2_realtime"
    headers = {"xi-api-key": os.getenv("ELEVENLABS_API_KEY")}

    async with websockets.connect(url, additional_headers=headers) as ws:
        # Connection established, wait for session_started
        session_msg = await ws.recv()
        print(f"Session started: {session_msg}")

        # Read audio file (16 kHz, mono, 16-bit PCM, little-endian)
        with open("/path/to/audio.pcm", "rb") as f:
            audio_data = f.read()

        # Run sending and receiving concurrently
        await asyncio.gather(
            send_audio(ws, audio_data),
            receive_transcripts(ws)
        )


asyncio.run(transcribe())
```

**`Exemplo de WebSocket em TypeScript`**

```typescript title="Exemplo de WebSocket em TypeScript"
    // Use this example if you are unable to use the SDK
    import "dotenv/config";
    import * as fs from "node:fs";
    // Make sure to install the "ws" library beforehand
    import WebSocket from "ws";

    const uri = "wss://api.elevenlabs.io/v1/speech-to-text/realtime?model_id=scribe_v2_realtime";
    const websocket = new WebSocket(uri, {
      headers: {
        "xi-api-key": process.env.ELEVENLABS_API_KEY,
      },
    });

    websocket.on("open", async () => {
      console.log("WebSocket opened");
    });

    // Listen to the incoming message from the websocket connection
    websocket.on("message", function incoming(event) {
      const data = JSON.parse(event.toString());

      switch (data.message_type) {
        case "session_started":
          console.log("Session started", data);
          sendAudio();
          break;
        case "partial_transcript":
          console.log("Partial:", data);
          break;
        case "committed_transcript":
          console.log("Committed:", data);
          break;
        // Committed transcripts with word-level timestamps. Only received when "include_timestamps=true" is included in the query parameters
        case "committed_transcript_with_timestamps":
          console.log("Committed with timestamps:", data);
          websocket.close();
          break;
        default:
          console.log(data);
          break;
      }

    });

    async function sendAudio() {
      // 16 kHz, mono, 16-bit PCM, little-endian
      const pcmFilePath = "/path/to/audio.pcm";

      const chunkSize = 32000; // 1 second of 16kHz audio (16000 samples * 2 bytes per sample)

      // Read the entire file into a buffer
      const audioBuffer = fs.readFileSync(pcmFilePath);

      // Split the buffer into chunks of exactly chunkSize bytes
      const chunks: Buffer[] = [];
      for (let i = 0; i < audioBuffer.length; i += chunkSize) {
        const chunk = audioBuffer.subarray(i, i + chunkSize);
        chunks.push(chunk);
      }

      // Send each chunk via websocket payload
      for (let i = 0; i < chunks.length; i++) {
        const chunk = chunks[i];
        const chunkBase64 = chunk.toString("base64");

        websocket.send(JSON.stringify({
          message_type: "input_audio_chunk",
          audio_base_64: chunkBase64,
          commit: false,
          sample_rate: 16000,
        }));

        // Wait 1 second between chunks to simulate real-time streaming
        // (each chunk contains 1 second of audio at 16kHz)
        if (i < chunks.length - 1) {
          await new Promise(resolve => setTimeout(resolve, 1000));
        }
      }

      // Small delay before final commit to let the last chunk process
      await new Promise(resolve => setTimeout(resolve, 500));

      // send final commit
      websocket.send(JSON.stringify({
        message_type: "input_audio_chunk",
        audio_base_64: "",
        commit: true,
        sample_rate: 16000,
      }));
    }
```

#### Execute o código

```python
python example.py
```

```typescript
npx tsx example.mts
```

Você verá a transcrição do arquivo de áudio impressa no console em transcrições parciais e confirmadas.

## Próximas etapas

#### [Transcrições e estratégias de confirmação](/docs/pt/eleven-api/guides/how-to/speech-to-text/realtime/transcripts-and-commit-strategies)

Controle quando as transcrições são confirmadas e como lidar com resultados parciais.

#### [Referência de eventos](/docs/pt/eleven-api/guides/how-to/speech-to-text/realtime/event-reference)

Lista completa de eventos e tipos de erro da API de STT em tempo real.