Partial transcripts
A partial transcript is the text of the utterance being spoken, so far. It changes as more is heard, until the utterance ends and its final transcript arrives. Partials make live captions feel instant and let a voice agent start thinking before the speaker pauses.
They are off by default. Turn them on in the init body:
{ "messages_config": { "receive_partial_transcripts": true } }Partials and the final of an utterance share its data.id: replace the displayed text of that id with each new
message, and keep the final. Each program prints both:
# pip install gladiaio-sdkimport osimport sysimport threadingimport wave
from gladiaio_sdk import GladiaClient, LiveV2InitRequest
API_URL = os.environ.get("GLADIA_API_URL", "https://eu1.api.gladia.io")API_KEY = os.environ["GLADIA_API_KEY"]
with wave.open(sys.argv[1]) as wav: # a 16-bit PCM WAV file rate, channels = wav.getframerate(), wav.getnchannels() audio = wav.readframes(wav.getnframes())
config = { "encoding": "wav/pcm", "sample_rate": rate, "bit_depth": 16, "channels": channels, "model": "solaria-3", "language_config": { "languages": [ "en" ] }, "messages_config": { "receive_partial_transcripts": True }}
client = GladiaClient(api_key=API_KEY, api_url=API_URL)session = client.live_v2().start_session(LiveV2InitRequest.from_dict(config))ended, errors = threading.Event(), []
@session.on("message")def on_message(message): if message.type == "transcript": kind = "final " if message.data.is_final else "partial" print(kind, message.data.id, message.data.utterance.text)
session.on("error", errors.append)session.once("ended", lambda _: ended.set())
step = rate * channels * 2 // 10 # 100 ms of audio per chunkfor start in range(0, len(audio), step): session.send_audio(audio[start : start + step]) # live audio: send each chunk as it is capturedsession.stop_recording()
ended.wait(timeout=60)sys.exit(1 if errors or not ended.is_set() else 0)// npm install @gladiaio/sdkimport { readFileSync } from "node:fs";import { GladiaClient } from "@gladiaio/sdk";
const { sampleRate, channels, pcm } = readWav(process.argv[2]); // a 16-bit PCM WAV file
const config = { encoding: "wav/pcm", sample_rate: sampleRate, bit_depth: 16, channels, model: "solaria-3", language_config: { languages: [ "en" ] }, messages_config: { receive_partial_transcripts: true }};
const client = new GladiaClient({ apiKey: process.env.GLADIA_API_KEY, apiUrl: process.env.GLADIA_API_URL ?? "https://eu1.api.gladia.io",});const session = client.liveV2().startSession(config);
session.on("message", (message) => { if (message.type === "transcript") { const kind = message.data.is_final ? "final " : "partial"; console.log(kind, message.data.id, message.data.utterance.text); }});session.on("error", (error) => { console.error(error); process.exitCode = 1;});session.once("ended", () => process.exit());
const step = (sampleRate * channels * 2) / 10; // 100 ms of audio per chunkfor (let start = 0; start < pcm.length; start += step) { session.sendAudio(pcm.subarray(start, start + step)); // live audio: send each chunk as it is captured}session.stopRecording();
function readWav(path) { const file = readFileSync(path); let fmt, pcm; for (let pos = 12; pos < file.length; ) { const id = file.toString("ascii", pos, pos + 4); const size = file.readUInt32LE(pos + 4); if (id === "fmt ") fmt = { channels: file.readUInt16LE(pos + 10), sampleRate: file.readUInt32LE(pos + 12) }; if (id === "data") pcm = file.subarray(pos + 8, pos + 8 + size); pos += 8 + size + (size % 2); } return { ...fmt, pcm };}Create the session, then stream its audio to the returned url (Live WebSocket):
curl -X POST https://eu1.api.gladia.io/v2/live \ -H "x-gladia-key: $GLADIA_API_KEY" \ -H "content-type: application/json" \ -d '{ "encoding": "wav/pcm", "sample_rate": 16000, "bit_depth": 16, "channels": 1, "model": "solaria-3", "language_config": { "languages": [ "en" ] }, "messages_config": { "receive_partial_transcripts": true } }'Limits and gotchas
Section titled “Limits and gotchas”- Partials are not final: words may change, and confidence is lower. Store and process the finals only.
- Do not append partials: replace the text of their
id. Appending them gives repeated words on screen. - More messages, more traffic: a partial comes several times a second per speaker. Turn them off
(
receive_partial_transcripts: false, the default) if you only store transcripts. - With PII redaction, no partial is sent: only the finals are redacted.
- The latency profile decides how often partials come:
fastsends them earliest. - Partials can also go to your callback (
callback_config.receive_partial_transcripts).