Streaming transcription

WSwss://api.lucidweights.ai/v1/stt/stream

Real-time streaming transcription. The server detects end-of-speech and emits a final transcript per utterance. You do not need to signal turn boundaries.

Connect

wss://api.lucidweights.ai/v1/stt/stream?api_key=KEY&sample_rate=16000&languages=en

Query parameters

FieldTypeDefaultDescription
api_keystringrequiredRequired in the query string, not a header
sample_rateint16000Sample rate of the PCM you send
backendstringultraultra, fast, or normal
model_namestringlargeFor fast/normal backends
languagesstring""Comma-separated ISO codes
enable_interim_transcriptboolfalseEmit non-final partial results
silence_thresholdint (ms)800Trailing silence that ends a turn
vad_thresholdfloat0.6Speech-detection sensitivity (higher = stricter)
enable_turn_takerboolfalseSemantic end-of-turn model. Ends turns sooner than silence alone
turn_taker_thresholdfloat0.55Confidence to end a turn early
wait_end_digitint (ms)500Extra hold when transcript ends in a number
audio_gainfloat1Linear gain before processing, clipped at ±1.0
auto_detect_sample_rateboolfalseInfer rate from packet timing

Sending audio

JSON text frames only. Binary frames are not read.

FieldTypeDefaultDescription
audio_datastringrequiredBase64 of 16-bit signed LE PCM, mono, at sample_rate
client_send_timestampint-Client epoch ms. Required for meaningful ctos_latency on finals
{
  "audio_data": "<base64 int16 PCM>",
  "client_send_timestamp": 1721470000000
}

There is no end-of-stream message. Close the socket. Pending audio is flushed after silence_threshold ms of inactivity.

Receiving transcripts

Interim (when enable_interim_transcript=true):

{ "transcription": "hello wor", "final": false }

Final:

{
  "transcription": "hello world",
  "final": true,
  "send_timestamp_ms": 1721470001234,
  "ctos_latency": 42,
  "vad_run_count": 0,
  "total_vad_proccesing_time": 0
}
NOTE
ctos_latency appears only on turn-end finals, not inactivity flushes. Empty transcripts are never sent.
WARNING
No µ-law mode on the stream. G.711 callers must expand to PCM16 client-side. Mono 16-bit signed integer only. Three consecutive failed utterances end the stream with close code 1011.
Example
import asyncio, base64, json, time, websockets

URL = (f"wss://api.lucidweights.ai/v1/stt/stream"
       f"?api_key=YOUR_KEY&sample_rate=16000&languages=en")

async def main():
    async with websockets.connect(URL) as ws:
        async def send():
            for chunk in pcm16_chunks():  # bytes, 16-bit LE mono
                await ws.send(json.dumps({
                    "audio_data": base64.b64encode(chunk).decode(),
                    "client_send_timestamp": int(time.time() * 1000),
                }))

        async def recv():
            async for msg in ws:
                d = json.loads(msg)
                if d.get("final"):
                    print("FINAL:", d["transcription"])

        await asyncio.gather(send(), recv())

asyncio.run(main())