AssemblyAI

Stream live microphone audio to AssemblyAI for real-time cloud transcription using decibri with the official AssemblyAI SDK. This page covers both Python and Node.js. Tabs above each code block switch between them.

What this does

This integration captures live audio from your microphone using decibri and streams it to AssemblyAI's cloud API. Transcription results return in real-time using a turn-based model, where speech is grouped into natural segments with partial and final results for each turn. There is no model download, no local inference, and no format conversion required.

Cloud vs local

Note: AssemblyAI is a cloud service. Audio is sent to AssemblyAI's servers for processing. An EU endpoint is available at streaming.eu.assemblyai.com for data residency requirements. If your use case requires audio to stay entirely on-device, use the local integrations: sherpa-onnx (real-time streaming) or whisper.cpp (batch transcription).

Prerequisites

Get an API key

  1. Sign up at assemblyai.com
  2. Upgrade your account (Settings > Billing > add a payment method). Streaming is only available on upgraded accounts.
  3. Copy your API key from the dashboard
  4. Store it in a .env file in your project root:
ASSEMBLYAI_API_KEY=your_key_here

Install packages

$ pip install decibri assemblyai python-dotenv

The dotenv package (python-dotenv on PyPI, dotenv on npm) loads your API key from the .env file. If you set environment variables another way, you can skip it. The install command above switches with the language tabs in the code blocks below.

No model download is required. All processing happens in AssemblyAI's cloud.

Code walkthrough

1. Configuration

Import decibri, the AssemblyAI SDK, and dotenv. Create a client with your API key.

import os
from dotenv import load_dotenv
import decibri
from assemblyai.streaming.v3 import (
    StreamingClient,
    StreamingClientOptions,
    StreamingEvents,
    StreamingParameters,
)

load_dotenv()
client = StreamingClient(
    StreamingClientOptions(api_key=os.environ["ASSEMBLYAI_API_KEY"])
)

2. Create streaming transcriber

Configure the streaming session. The speech model is required and has no default; omitting it causes the connection to fail. The Python SDK builds these into a StreamingParameters object passed at connect time; the Node SDK passes them to client.streaming.transcriber().

params = StreamingParameters(sample_rate=16000, speech_model="u3-rt-pro")

3. Register event handlers

Register handlers before connecting. This ensures no events are missed during the connection handshake. Both SDKs expose at least turn and error events; the Node SDK additionally exposes open and close.

def on_turn(client, event):
    if event.end_of_turn and event.transcript:
        print(event.transcript)

def on_error(client, error):
    print(f"AssemblyAI error: {error}")

client.on(StreamingEvents.Turn, on_turn)
client.on(StreamingEvents.Error, on_error)

4. Connect and open microphone

Note: AssemblyAI streaming v3 requires audio chunks between 50 ms and 1000 ms (error 3007 on violation). On Windows, decibri's audio backend may emit chunks shorter than 50 ms regardless of frames_per_buffer / framesPerBuffer. The streaming code block below batches incoming audio into 100 ms (3200 bytes of int16 mono 16 kHz) before forwarding to AssemblyAI, and drops any trailing remainder under 50 ms (1600 bytes).

Connect to AssemblyAI, then prepare the microphone. In Python the connect call is synchronous and Microphone is only constructed here; capture starts in the next block when it is opened with a with statement. In Node the connect call returns a promise that must be awaited, and new Microphone(...) begins capture as soon as it is constructed. Audio must only be sent after the connection is established.

client.connect(params)
mic = decibri.Microphone(sample_rate=16000, channels=1)

5. Stream audio

Read chunks from decibri and forward them to AssemblyAI. AssemblyAI streaming v3 requires audio in 50 ms to 1000 ms windows; decibri on Windows may emit chunks shorter than 50 ms, so batch incoming audio into 100 ms (3200 bytes of int16 mono at 16 kHz) before forwarding. Drop any trailing remainder under 50 ms (1600 bytes). No format conversion is needed; decibri produces raw int16 PCM which AssemblyAI accepts as-is.

BATCH_BYTES = 3200   # 100 ms of int16 mono at 16 kHz
MIN_BYTES = 1600     # 50 ms; AssemblyAI streaming v3 minimum

def audio_iter():
    buffer = bytearray()
    for chunk in mic:
        buffer.extend(chunk)
        while len(buffer) >= BATCH_BYTES:
            yield bytes(buffer[:BATCH_BYTES])
            del buffer[:BATCH_BYTES]
    if len(buffer) >= MIN_BYTES:
        yield bytes(buffer)

6. Understanding turn-based results

AssemblyAI groups speech into turns, which are natural segments of speech separated by pauses. Each turn emits multiple events as audio is processed:

The event object exposes the same fields in both SDKs; only the callback parameter name differs (event in Python, turn in Node).

To show only final results, filter on end_of_turn:

def on_turn(client, event):
    if event.end_of_turn and event.transcript:
        print(event.transcript)

7. Clean shutdown

Stop the microphone and close the AssemblyAI connection when the user presses Ctrl+C.

print("Listening... (Ctrl+C to stop)")
try:
    with mic:
        client.stream(audio_iter())
except KeyboardInterrupt:
    print("\nStopping...")
finally:
    client.disconnect(terminate=True)

Full example

View complete code
import os
from dotenv import load_dotenv

import decibri
from assemblyai.streaming.v3 import (
    StreamingClient,
    StreamingClientOptions,
    StreamingEvents,
    StreamingParameters,
)

BATCH_BYTES = 3200   # 100 ms of int16 mono at 16 kHz
MIN_BYTES = 1600     # 50 ms; AssemblyAI streaming v3 minimum

load_dotenv()

client = StreamingClient(
    StreamingClientOptions(api_key=os.environ["ASSEMBLYAI_API_KEY"])
)

def on_turn(client, event):
    if event.end_of_turn and event.transcript:
        print(event.transcript)

def on_error(client, error):
    print(f"AssemblyAI error: {error}")

client.on(StreamingEvents.Turn, on_turn)
client.on(StreamingEvents.Error, on_error)

client.connect(StreamingParameters(sample_rate=16000, speech_model="u3-rt-pro"))

mic = decibri.Microphone(sample_rate=16000, channels=1)

def audio_iter():
    buffer = bytearray()
    for chunk in mic:
        buffer.extend(chunk)
        while len(buffer) >= BATCH_BYTES:
            yield bytes(buffer[:BATCH_BYTES])
            del buffer[:BATCH_BYTES]
    if len(buffer) >= MIN_BYTES:
        yield bytes(buffer)

print("Listening... (Ctrl+C to stop)")
try:
    with mic:
        client.stream(audio_iter())
except KeyboardInterrupt:
    print("\nStopping...")
finally:
    client.disconnect(terminate=True)

Configuration options

The transcriber options control how AssemblyAI processes your audio. Names differ slightly between SDKs (Python uses snake_case, Node uses camelCase) but the meaning is identical. Here are the key ones:

Option Value Description
speech_model / speechModel 'u3-rt-pro' Required. Universal-3 Pro Streaming model.
sample_rate / sampleRate 16000 Must match decibri's sample rate.

Additional options such as keyterm prompting and speaker diarization are available. See the AssemblyAI streaming documentation for the complete list.