Sections

Streaming

Streaming SDK

The meetwave-stream client for JavaScript and Python: keeps audio while it connects, reconnects without losing words and waits for the transcript at stop.

Install

npm install meetwave-stream for Node 22 or later and browsers, with no dependencies. pip install meetwave-stream for Python 3.10 or later. Both have the same shape; Python names are in snake case (api_key, wait_for_transcript).

# pip install meetwave-stream      (Python 3.10 or later)
# export MEETWAVE_API_KEY=mwk_...   (your key, from the console)
import asyncio
import os

import meetwave_stream


def show_ready(ready):
    print("Connected, streaming…")


def show_final(final):
    print(f"[{final['start']:.1f} s] {final['text']}")


async def main():
    session = meetwave_stream.connect(
        api_key=os.environ["MEETWAVE_API_KEY"], tier="names", language="en",
    )
    session.on("ready", show_ready)
    session.on("final", show_final)
    with open("meeting.pcm", "rb") as file:  # 16 kHz mono 16-bit PCM
        while chunk := file.read(3200):
            # Any size; what is sent before the server is ready is kept for it
            session.send(chunk)
            await asyncio.sleep(0.1)
    result = await session.stop()  # waits for the full transcript
    for segment in result.transcript["segments"]:
        print(segment["speaker"], segment["text"])


asyncio.run(main())

What it does for you

  • Keeps the audio you send before the connection is ready, up to 1 minute, and sends it then: the first words of a call are not lost while the server starts.
  • Keeps up to 2 minutes of audio the server has not yet stored. When the connection drops (codes 1001, 1006, 1011, 1012, 1013) it reconnects, up to 6 times, 0.5 to 8 seconds apart, and resends it. Nothing is charged twice and no final repeats.
  • Its stop() waits for the full transcript, with speakers and names on those tiers.

Options

OptionTypeMeaning
apiKeymwk_…Your key. On a server only.
tokenstring | () => Promise<string>In a browser, instead of a key: a one-time token, or a function that fetches one (needed to reconnect).
tiertext | speakers | namesDefaults to text.
languageen | a code | autoDefaults to en. Live text in en, es, pt, ru, de, fr, it (de, fr, it as a preview); any other code, or auto, gets its text at stop. The client names it in the connection address too, so the first text comes sooner.
waitForTranscriptbooleanWhether stop() waits for the full transcript. On when there is a key; a browser has none to read it with.
transcriptTimeoutMsnumberHow long stop() waits for it. Defaults to 30 minutes.

Methods

MethodReturnsMeaning
send(pcm)boolean16 kHz mono 16-bit PCM, any chunk size. False once the session is stopping or over.
sendFloat32(samples, rate)booleanFloat samples at any rate, such as a browser’s microphone; converted for you.
stop()PromiseSends the rest, ends the session and resolves to transcriptId, status, audioSeconds and transcript.
close()voidEnds the connection at once, without the last phrase or the transcript.
on(event, listener)sessionListens to one of the events below; off() removes a listener.

Events

EventCarriesMeaning
readysessionId, transcriptId, live, resumedConnected; audio kept so far is on its way.
partialtext, start, endThe phrase so far; the next partial replaces it.
finaltext, start, end, wordsA finished phrase, never repeated after a reconnect.
warningcode, seconds_leftYour credits are running low.
reconnectingattempt, delayMs, closeCodeThe connection dropped; the client tries again.
errorcode, closeCode, messageThe session ended with an error and will not reconnect.
closedcodeThe connection is closed for good.

In a browser

The page never holds your key. Your server creates a one-time token for each connection (see Streaming), and the client asks for one whenever it connects:

import { connect } from "meetwave-stream";

// Your server calls POST /v1/stream/tokens with your key and returns the token.
// A function, not a string: a resumed connection asks for a fresh one.
async function token() {
  const response = await fetch("/stream-token", { method: "POST" });
  return (await response.json()).token;
}

const session = connect({ token, tier: "text", language: "en" });
session.on("partial", (partial) => (caption.textContent = partial.text));
session.on("final", (final) => transcript.append(final.text + " "));

// Microphone samples from an AudioWorklet, at the device's own rate
worklet.port.onmessage = (event) => {
  session.sendFloat32(event.data, audioContext.sampleRate);
};

// Without a key the client does not wait for the transcript:
// your server reads it by its id
stopButton.onclick = async () => {
  const { transcriptId } = await session.stop();
  await saveTranscriptId(transcriptId);
};

Every message the client sends and receives is described on the protocol page, for any language without a client.