This section as Markdown: View Download

Realtime Speech to Text

Transcribe live microphone audio into text in real time using streaming ASR models.

Overview

Realtime speech-to-text models convert streaming audio into text transcripts as the user speaks. Unlike Realtime Voice Conversation which produces two-way audio, this mode is audio in → text out only. There is no AI audio playback — the server returns transcript strings over the WebSocket.

The flow is:

  1. Run the realtime STT model via POST /Run to get a socketaccesstoken
  2. Connect to the WebSocket and send task_info with your token
  3. Wait for task_stream_ready — the model is ready to receive audio
  4. Stream microphone audio as binary frames (client → server)
  5. Receive transcript text as task_output messages with TRANSCRIPT_USER: prefix
  6. End the session with task_session_end

Key difference from Voice Conversation: No binary audio is sent back from the server. All server → client messages are JSON text events.

How It Differs from Realtime Voice Conversation

Realtime Voice Conversation Realtime Speech to Text
Input Microphone audio (streamed) Microphone audio (streamed)
Output AI audio + transcripts Transcript text only
Direction Bidirectional (client ↔ server) Client → server audio, server → client text
Binary frames from server Yes (AI audio) No (all server messages are JSON)
Transcripts TRANSCRIPT_USER: and TRANSCRIPT_AI: TRANSCRIPT_USER: only
Use case Interactive voice chat Live dictation, captioning, meeting transcription

Run Parameters

Each realtime STT model has its own set of parameters. Use POST /Tool/Detail to discover the exact parameters for a specific model. See Model Parameters for parameter types.

Browse available realtime STT models on the models page (filter by Realtime STT category). Common parameters typically include a transcription delay setting that trades speed for accuracy; some models also take a language. Example run for Voxtral Mini 4B Realtime:

curl -X POST "https://api.wiro.ai/v1/Run/mistralai/voxtral-mini-4b-realtime-2602" \
  -H "Content-Type: application/json" \
  -H "x-api-key: YOUR_API_KEY" \
  -d '{
    "transcriptionDelay": "balanced"
  }'

Important: Parameters vary per model. Always check the model's detail page or use /Tool/Detail to get the exact parameter list before integrating. The run response returns a socketaccesstoken used to subscribe to the WebSocket.

Connection & Registration

After running the task, connect to the WebSocket and register with task_info:

var ws = new WebSocket("wss://socket.wiro.ai/v1");

ws.onopen = function() {
  ws.send(JSON.stringify({
    type: "task_info",
    tasktoken: "YOUR_SOCKET_ACCESS_TOKEN"
  }));
};

Note: Both standard and realtime models use type: "task_info" with tasktoken to register on the WebSocket.

Realtime Events

During a realtime speech-to-text session, you'll receive these WebSocket events:

Event Direction Description
task_stream_ready server → client Session is ready — start sending microphone audio
task_output server → client Transcript text prefixed with TRANSCRIPT_USER:
task_stream_end server → client Transcription stream has ended — no more transcripts will arrive
task_cost server → client Cost update — includes turnCost, cumulativeCost, and usage breakdown
task_end server → client The model process has exited. Post-processing follows — wait for task_postprocess_end before closing.
task_postprocess_end server → client Post-processing complete — safe to close the WebSocket now.

Unlike voice conversation, there are no binary audio frames from the server. Every server message is a JSON text event.

Audio Format

Audio flows in one direction only: client → server.

Property Value
Format PCM (raw, uncompressed)
Bit depth 16-bit signed integer (Int16)
Sample rate 24,000 Hz (24 kHz)
Channels Mono (1 channel)
Byte order Little-endian
Chunk size 4,800 samples (200 ms) = 9,600 bytes

The server internally resamples to the model's native rate (e.g. 16 kHz for Voxtral). Always send at 24 kHz — the server handles conversion.

Binary Frame Format

Every binary WebSocket frame sent from the client is structured as:

[tasktoken]|[PCM audio data]

The pipe character | (0x7C) separates the token from the raw audio bytes. There are no binary frames from the server — all responses are JSON text.

Sending Microphone Audio

Capture microphone audio at 24 kHz using the Web Audio API with an AudioWorklet. Convert Float32 samples to Int16, prepend your task token, and send as a binary frame.

Key steps:

  1. Request microphone with getUserMedia (enable echo cancellation and noise suppression)
  2. Create an AudioContext at 24,000 Hz sample rate
  3. Use an AudioWorklet to buffer and convert samples to Int16
  4. Send each chunk as tasktoken|pcm_data binary frame
  5. Continue sending until you end the session

Tip: You can send audio continuously — the model handles silence detection and only returns transcripts when speech is detected.

Transcripts

Transcripts arrive as task_output messages with the TRANSCRIPT_USER: prefix. Each message contains a segment of transcribed speech:

{
  "type": "task_output",
  "message": "TRANSCRIPT_USER:What's the weather like today?"
}

{
  "type": "task_output",
  "message": "TRANSCRIPT_USER:I need to book a flight to New York."
}

Progressive Results

Transcripts arrive progressively as words and phrases are recognized — not just at segment boundaries. The model streams TRANSCRIPT_USER: messages word-by-word as speech is detected, so the client can display live, incremental results. To build a full transcript, concatenate all received messages:

var fullTranscript = [];

// Inside your message handler
if (msg.type === 'task_output' &&
    typeof msg.message === 'string' &&
    msg.message.startsWith('TRANSCRIPT_USER:')) {
  var segment = msg.message.substring(16);
  fullTranscript.push(segment);
  console.log('Segment:', segment);
  console.log('Full:', fullTranscript.join(' '));
}

Note: Unlike voice conversation, there is no TRANSCRIPT_AI: prefix. All transcripts are user speech.

Ending a Session

To gracefully end a realtime session, send task_session_end:

{
  "type": "task_session_end",
  "tasktoken": "YOUR_SOCKET_ACCESS_TOKEN"
}

After sending this, the server processes any remaining buffered audio, sends final transcript and cost events, and then emits task_postprocess_end. Wait for task_postprocess_end before closing the WebSocket.

Safety: If the client disconnects without sending task_session_end, the server automatically terminates the session to prevent the pipeline from running indefinitely (and the provider from continuing to charge). Always send task_session_end explicitly for a clean shutdown.

Insufficient balance: The session is charged turn by turn as it runs. When a charged turn uses up your available balance (the team wallet's balance when you use a team project's API key), the server stops the session right after that turn. That turn is charged in full, and so is any final usage reported while the session closes, so your balance can end slightly below zero. You still receive the final task_cost and task_end events.