Code Examples
Python — transcribe a file
Uses websockets and requests.
import asyncio
import json
import requests
import websockets
API_BASE = "https://api.scriptix.io"
REALTIME_WS = "wss://realtime.scriptix.io/v2/realtime"
TOKEN = "YOUR_REALTIME_TOKEN"
def get_language_code(preferred: str) -> str:
"""Return an available language code for the given preferred language."""
resp = requests.get(
f"{API_BASE}/api/v3/speech_to_text/realtime/languages",
headers={"x-zoom-s2t-key": TOKEN},
)
resp.raise_for_status()
result = resp.json()["result"]
languages = result["languages"]
# Match preferred language against available codes
for code in languages:
if code.startswith(preferred):
return code
raise ValueError(f"Language '{preferred}' not available. Options: {languages}")
async def transcribe_file(path: str, language: str = "en") -> str:
lang_code = get_language_code(language)
print(f"Language: {lang_code}")
uri = f"{REALTIME_WS}?language={lang_code}"
headers = {"x-zoom-s2t-key": TOKEN}
with open(path, "rb") as f:
audio = f.read()
transcripts = []
async with websockets.connect(uri, additional_headers=headers) as ws:
# Start
await ws.send(json.dumps({"action": "start"}))
msg = json.loads(await ws.recv())
assert msg.get("state") == "listening", f"Unexpected: {msg}"
# Stream in ~1-second chunks
chunk_size = 32 * 1024
for offset in range(0, len(audio), chunk_size):
await ws.send(audio[offset : offset + chunk_size])
# Stop
await ws.send(json.dumps({"action": "stop"}))
# Collect remaining results
async for raw in ws:
msg = json.loads(raw)
if msg.get("state") == "stopped":
break
if "text" in msg:
transcripts.append(msg["text"])
return " ".join(transcripts)
if __name__ == "__main__":
text = asyncio.run(transcribe_file("audio.wav", language="en"))
print(text)
JavaScript / Node.js — transcribe a file
Uses the built-in ws package.
import WebSocket from "ws";
import { readFileSync } from "fs";
const API_BASE = "https://api.scriptix.io";
const REALTIME_WS = "wss://realtime.scriptix.io/v2/realtime";
const TOKEN = "YOUR_REALTIME_TOKEN";
async function getLanguageCode(preferred = "en") {
const res = await fetch(
`${API_BASE}/api/v3/speech_to_text/realtime/languages`,
{ headers: { "x-zoom-s2t-key": TOKEN } }
);
const { result } = await res.json();
const code = result.languages.find((l) => l.startsWith(preferred));
if (!code) throw new Error(`Language '${preferred}' not available: ${result.languages}`);
return code;
}
async function transcribeFile(filePath, language = "en") {
const code = await getLanguageCode(language);
console.log(`Language: ${code}`);
const audio = readFileSync(filePath);
const CHUNK = 32 * 1024; // ~1 second at 16kHz
const transcripts = [];
await new Promise((resolve, reject) => {
const ws = new WebSocket(`${REALTIME_WS}?language=${code}`, {
headers: { "x-zoom-s2t-key": TOKEN },
});
ws.on("open", () => ws.send(JSON.stringify({ action: "start" })));
ws.on("message", (data) => {
const msg = JSON.parse(data);
if (msg.state === "listening") {
for (let i = 0; i < audio.length; i += CHUNK) {
ws.send(audio.slice(i, i + CHUNK));
}
ws.send(JSON.stringify({ action: "stop" }));
} else if (msg.text) {
transcripts.push(msg.text);
} else if (msg.state === "stopped") {
ws.close();
}
});
ws.on("close", resolve);
ws.on("error", reject);
});
return transcripts.join(" ");
}
const text = await transcribeFile("audio.wav", "en");
console.log(text);
Browser — live microphone captions
Browsers cannot set custom headers on WebSocket connections. Use ?token= instead.
<!DOCTYPE html>
<html>
<head><title>Live Captions</title></head>
<body>
<button id="start">Start</button>
<button id="stop" disabled>Stop</button>
<p id="transcript"></p>
<script>
const TOKEN = "YOUR_REALTIME_TOKEN";
const LANGUAGE = "en"; // must match a code from /realtime/languages
const WS_URL = `wss://realtime.scriptix.io/v2/realtime?language=${LANGUAGE}&token=${TOKEN}`;
let ws, audioContext, processor, stream;
document.getElementById("start").onclick = async () => {
stream = await navigator.mediaDevices.getUserMedia({ audio: true });
audioContext = new AudioContext({ sampleRate: 16000 });
const source = audioContext.createMediaStreamSource(stream);
processor = audioContext.createScriptProcessor(4096, 1, 1);
processor.onaudioprocess = (e) => {
const float32 = e.inputBuffer.getChannelData(0);
const int16 = new Int16Array(float32.length);
for (let i = 0; i < float32.length; i++) {
int16[i] = Math.max(-32768, Math.min(32767, float32[i] * 32768));
}
if (ws?.readyState === WebSocket.OPEN) ws.send(int16.buffer);
};
source.connect(processor);
processor.connect(audioContext.destination);
ws = new WebSocket(WS_URL);
ws.onopen = () => ws.send(JSON.stringify({ action: "start" }));
ws.onmessage = ({ data }) => {
const msg = JSON.parse(data);
if (msg.text) document.getElementById("transcript").textContent = msg.text;
};
document.getElementById("start").disabled = true;
document.getElementById("stop").disabled = false;
};
document.getElementById("stop").onclick = () => {
ws?.send(JSON.stringify({ action: "stop" }));
stream?.getTracks().forEach((t) => t.stop());
processor?.disconnect();
document.getElementById("start").disabled = false;
document.getElementById("stop").disabled = true;
};
</script>
</body>
</html>