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
| Option | Type | Meaning |
|---|---|---|
apiKey | mwk_… | Your key. On a server only. |
token | string | () => Promise<string> | In a browser, instead of a key: a one-time token, or a function that fetches one (needed to reconnect). |
tier | text | speakers | names | Defaults to text. |
language | en | a code | auto | Defaults 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. |
waitForTranscript | boolean | Whether stop() waits for the full transcript. On when there is a key; a browser has none to read it with. |
transcriptTimeoutMs | number | How long stop() waits for it. Defaults to 30 minutes. |
Methods
| Method | Returns | Meaning |
|---|---|---|
send(pcm) | boolean | 16 kHz mono 16-bit PCM, any chunk size. False once the session is stopping or over. |
sendFloat32(samples, rate) | boolean | Float samples at any rate, such as a browser’s microphone; converted for you. |
stop() | Promise | Sends the rest, ends the session and resolves to transcriptId, status, audioSeconds and transcript. |
close() | void | Ends the connection at once, without the last phrase or the transcript. |
on(event, listener) | session | Listens to one of the events below; off() removes a listener. |
Events
| Event | Carries | Meaning |
|---|---|---|
ready | sessionId, transcriptId, live, resumed | Connected; audio kept so far is on its way. |
partial | text, start, end | The phrase so far; the next partial replaces it. |
final | text, start, end, words | A finished phrase, never repeated after a reconnect. |
warning | code, seconds_left | Your credits are running low. |
reconnecting | attempt, delayMs, closeCode | The connection dropped; the client tries again. |
error | code, closeCode, message | The session ended with an error and will not reconnect. |
closed | code | The 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.