Skip to content

Instantly share code, notes, and snippets.

@solarkraft
Last active December 26, 2025 03:28
Show Gist options
  • Select an option

  • Save solarkraft/2d4b42c8d3fbd0c985ed7f8a87420d29 to your computer and use it in GitHub Desktop.

Select an option

Save solarkraft/2d4b42c8d3fbd0c985ed7f8a87420d29 to your computer and use it in GitHub Desktop.
Simple demo of live audio transcription using the Deepgram Live Audio API (api.deepgram.com/v1/listen) via the Deepgram SDK
<!DOCTYPE html>
<html>
<head>
<title>Deepgram Live Demo</title>
<script src="https://cdn.jsdelivr.net/npm/@deepgram/sdk@v4.11.2"></script>
<style>
body {
font-family: sans-serif;
max-width: 60rem;
margin: 3rem auto;
line-height: 1.5;
text-align: left;
}
label {
display: inline-block;
width: 6rem;
}
input {
padding: 0.5rem;
font-size: 1rem;
border-radius: 0.25rem;
border: 1px solid #ccc;
}
button {
padding: 0.5rem;
font-size: 1rem;
}
.api-input {
width: 20rem;
}
#captions {
margin-top: 2rem;
padding: 1.5rem;
border: 1px solid #ccc;
border-radius: 0.5rem;
min-height: 10rem;
font-size: 1.5rem;
font-family: serif;
}
.interim {
color: #666;
font-style: italic;
}
.placeholder {
color: #666;
}
.status-recording #captions {
box-shadow: 0 0 0.5rem #007bff;
}
</style>
</head>
<body>
<h1>Deepgram Live Demo</h1>
<p>
This is a simple demo of live audio transcription using the <a
href="https://developers.deepgram.com/reference/speech-to-text/listen-streaming" target="_blank">Deepgram
Live Audio API</a> with the <a href="https://github.com/deepgram/sdk-js" target="_blank">Deepgram SDK</a>.
</p>
<p>This demo outputs Opus encoded audio, which is relatively simple and highly bandwidth efficient, but adds some
latency.</p>
<p>
Enter your base URL and your API key below, then click "Start Transcribing" to begin.
</p>
<p>
<label>Base URL:</label>
<input type="text" id="apiUrl" class="api-input" value="https://api.deepgram.com">
</p>
<p>
<label>API Key:</label>
<input type="password" id="apiKey" class="api-input">
</p>
<button id="record">Start Transcribing</button>
<div id="captions">
<span class="placeholder">Transcript will show up here ...</span>
</div>
<script>
// Load saved API key and URL on page load
window.addEventListener('DOMContentLoaded', () => {
const savedApiKey = localStorage.getItem('deepgram_api_key');
if (savedApiKey) {
document.getElementById('apiKey').value = savedApiKey;
}
const savedApiUrl = localStorage.getItem('deepgram_api_url');
if (savedApiUrl) {
document.getElementById('apiUrl').value = savedApiUrl;
}
});
const captions = document.getElementById("captions");
const apiKeyInput = document.getElementById("apiKey");
const apiUrlInput = document.getElementById("apiUrl");
const recordButton = document.getElementById("record");
let microphone = null;
let liveClient = null;
let finalTranscript = ""; // Accumulate final results here
async function getMicrophone() {
const userMedia = await navigator.mediaDevices.getUserMedia({
audio: {
channelCount: 1,
sampleRate: 16000,
echoCancellation: true,
noiseSuppression: true,
},
});
return new MediaRecorder(userMedia);
}
async function openMicrophone(microphone, liveClient) {
await microphone.start(100);
microphone.onstart = () => {
console.log("client: microphone opened");
document.body.classList.add("status-recording");
recordButton.textContent = "Stop Transcribing";
};
microphone.onstop = () => {
console.log("client: microphone closed");
document.body.classList.remove("status-recording");
recordButton.textContent = "Start Transcribing";
};
microphone.ondataavailable = (e) => {
console.log("client: sent data to websocket");
liveClient.send(e.data);
};
}
async function closeMicrophone(microphone) {
microphone.stop();
}
async function startRecording() {
const apiKey = apiKeyInput.value.trim();
const apiUrl = apiUrlInput.value.trim();
if (!apiKey) {
alert("Please enter your Deepgram API key first.");
return;
}
if (!apiUrl) {
alert("Please enter the Deepgram API URL.");
return;
}
// Save API key and URL to localStorage
localStorage.setItem('deepgram_api_key', apiKey);
localStorage.setItem('deepgram_api_url', apiUrl);
const { createClient } = deepgram;
const client = createClient({
key: apiKey,
global: { url: apiUrl }
});
liveClient = client.listen.live({
model: "nova-2",
smart_format: true,
interim_results: true
});
liveClient.on("open", async () => {
console.log("client: connected to websocket");
liveClient.on("Results", (data) => {
// Check if we have the expected structure
if (!data.channel || !data.channel.alternatives || data.channel.alternatives.length === 0) {
return;
}
const transcript = data.channel.alternatives[0].transcript;
const isFinal = data.is_final;
console.log("Transcript:", transcript, "Full response:", data);
if (transcript) {
if (isFinal) {
finalTranscript += transcript + " ";
captions.innerHTML = `<span class="final">${finalTranscript}</span>`;
} else {
captions.innerHTML = `<span class="final">${finalTranscript}</span><span class="interim">${transcript}</span>`;
}
}
});
liveClient.on("error", (e) => {
console.error(e);
alert("Error: " + e.message);
});
liveClient.on("warning", (e) => console.warn(e));
liveClient.on("Metadata", (e) => console.log(e));
liveClient.on("close", (e) => {
console.log("LiveClient closed", e);
});
// Open microphone after socket is ready
microphone = await getMicrophone();
await openMicrophone(microphone, liveClient);
});
}
async function stopRecording() {
await closeMicrophone(microphone);
microphone = null;
if (liveClient) {
liveClient.requestClose();
liveClient = null;
}
}
recordButton.addEventListener("click", async () => {
if (!microphone) {
await startRecording();
} else {
await stopRecording();
}
});
</script>
</body>
</html>
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment