Streaming speech to text

Tapra-Voice-Realtime

Partial tokens while the sentence is still being spoken.

Tapra-Voice-Realtime is the streaming twin of Tapra-Voice: same code-switching behaviour, different delivery. The browser or your server opens one socket, ships 16 kHz PCM frames, and receives partial events as words are recognized, then a final transcript with the exact usage charge when you stop.

  • 0.300 TND / min
  • 16 kHz PCM
  • VAD + endpointing

WSS /v1/realtime/stream

Client sends

open → 100 ms PCM frames → {"type":"stop"}

Server events

ready 0.01 s → first partial 1.97 s → utterance 23.64 s → final 28.06 s (reason: client_stop)

Live output

Real output

Recorded from the live model.

Every output on this page came from tapra-voice-v1-realtime on 8 October 2026 and is shown unedited, mistakes included. Each live response also carries its exact charge in x-tapra-cost-tnd.

The 26-second code-switched voice note, streamed at real-time pace in 100 ms PCM frames. Every partial below is the event the server sent, at the moment it sent it.

0:00 / 0:00

Client sends · pcm_s16le 16 kHz

Server partials

final

نخمم نعمل une combinaison ما بين les deux modèles tomes canagent اللي هو capable يجاوب عل les clients كيما مثلا في الكنفيرما متاع les ordres والا تعمل marketing لهنا le modèle لازمو يكون قادر يعمل switch between languages ويجاوب زادا بنفس ال façon

Unedited stream. It mishears the same product name as the batch model ("tomes canagent"), and gets façon right where the batch transcript did not.

What it does

Capabilities you can build on today.

01

Silence VAD and turn endpointing

Live sessions mask silence before the decoder and emit an utterance event after about 800 ms of trailing pause. About 10 seconds of continuous silence auto-stops the session so idle microphones stop holding an ASR slot. Pass idle_stop=0 to keep listening.

02

No GPU cold start

Inference runs on commodity CPU instances. The first frame is served immediately: there is no warm-up window and no capacity you rent while idle.

03

Auth without leaking keys

Browser clients pass the WebSocket subprotocols tapra-realtime and tapra-auth.<API_KEY>. Server clients use Authorization: Bearer during the upgrade. Keys never belong in a URL.

04

Explicit session lifecycle

A ready event opens the session, partial events stream, {"type":"stop"} closes it with the final transcript and charge, and a ping every 15 seconds keeps connections alive when you are not sending audio. Ten seconds of silence also closes the session unless you pass idle_stop=0.

Integrate

The contract, in one place.

Model id
tapra-voice-v1-realtime
Endpoint
WSS /v1/realtime/stream?language=ar-AR
Client to server
Binary mono PCM frames, pcm_s16le, 16 kHz
Server to client
ready, partial, utterance, final, error events
Custom protocols
tapra-realtime, tapra-auth.<API_KEY>
VAD / endpointing
On by default; trailing silence ~800 ms emits utterance
Idle auto-stop
On by default; ~10 s of silence sends final and closes the socket
Keep-alive
{"type":"ping"} every 15 seconds when not sending audio
Close
{"type":"stop"} or idle auto-stop returns the final transcript and usage
Billing
Audio milliseconds streamed at 0.300 TND / min
Open a realtime streamts
const socket = new WebSocket(
  'wss://api.tapra.tn/v1/realtime/stream?language=ar-AR',
  ['tapra-realtime', 'tapra-auth.' + apiKey]
);

socket.onmessage = (event) => {
  const message = JSON.parse(event.data);
  if (message.type === 'partial') render(message.text);
  if (message.type === 'utterance') lockTurn(message.turn_text);
  if (message.type === 'final') console.log(message.text, message.usage);
};

// Push mono 16-bit PCM frames, then close the session cleanly.
socket.onopen = () => recorder.onFrame((frame) => socket.send(frame));
stopButton.onclick = () => socket.send(JSON.stringify({ type: 'stop' }));

Comparison

How Tapra-Voice-Realtime differs.

Compared with GPU-hosted realtime APIs and browser speech engines.

Tapra-Voice-Realtime compared with a generic alternative
CapabilityTapra-Voice-RealtimeGeneric alternative
Partial decode timeMedian 4 ms, p95 119 ms across 196 partials (recorded session)GPU warm-up curve; cold sessions stall for seconds
Idle costZero — metered on streamed audio onlyReserved GPU capacity billed while quiet
Code-switching mid-streamDarija, French, and English in one socketLocked to one language per session
Browser authWebSocket subprotocols, key never in the URLQuery-string tokens that end up in logs and referrers
Consistency with batchSame family as tapra-voice-v1, same transcript styleSeparate streaming model with different conventions
Cost0.300 TND / min (≈ $0.100), metered per sessionPer-minute floors and concurrency minimums

Pricing

Metered, never subscribed.

You pay for exactly what you send. The same prepaid balance covers all five Tapra models, billed in TND.

Headline rate

0.300 TND / min

One WebSocket that revises the transcript while you speak, then locks each turn after a pause. No idle infrastructure to pay for.

Rate
$0.100 per audio minute
In dinars
0.300 TND per audio minute
Hourly equivalent
$6.00 per hour
Metered unit
audio_ms (exact audio duration)
Minimum charge
None — no idle session fee

Questions

What builders ask first.

How do I authenticate from a browser?

Send the subprotocols tapra-realtime and tapra-auth.<API_KEY> when opening the socket. Never put a key in the query string — it would land in server logs and referrer headers.

What audio format does the socket expect?

Binary mono PCM frames encoded as pcm_s16le at 16 kHz. That is what the Tapra microphone capture already produces, so there is no resampling step.

What happens if the connection goes idle?

Send {"type":"ping"} every 15 seconds if you are not sending audio. After a pause of about 800 ms the server emits utterance and keeps listening. About 10 seconds of silence auto-stops the session (final with reason idle_stop) so it stops consuming a slot. Pass idle_stop=0 to disable that. When you are done, send {"type":"stop"} for the final transcript and usage charge.