Deepgram Core Workflow A: Pre-recorded Transcription
Overview
Production pre-recorded transcription service using Deepgram's REST API. Covers transcribeUrl and transcribeFile, speaker diarization, audio intelligence (summarization, topic detection, sentiment, intent), batch processing with concurrency control, and callback-based async transcription for large files.
Prerequisites
@deepgram/sdk installed, DEEPGRAM_API_KEY configured
- Audio files: WAV, MP3, FLAC, OGG, M4A, or WebM
- For batch:
p-limit package (npm install p-limit)
Instructions
Step 1: Transcription Service Class
import { createClient, DeepgramClient } from '@deepgram/sdk';
import { readFileSync } from 'fs';
interface TranscribeOptions {
model?: 'nova-3' | 'nova-2' | 'nova-2-meeting' | 'nova-2-phonecall' | 'base';
language?: string;
diarize?: boolean;
utterances?: boolean;
paragraphs?: boolean;
smart_format?: boolean;
summarize?: boolean; // Audio intelligence
detect_topics?: boolean; // Topic detection
sentiment?: boolean; // Sentiment analysis
intents?: boolean; // Intent recognition
keywords?: string[]; // Keyword boosting: ["term:weight"]
callback?: string; // Async callback URL
}
class DeepgramTranscriber {
private client: DeepgramClient;
constructor(apiKey: string) {
this.client = createClient(apiKey);
}
async transcribeUrl(url: string, opts: TranscribeOptions = {}) {
const { result, error } = await this.client.listen.prerecorded.transcribeUrl(
{ url },
{
model: opts.model ?? 'nova-3',
language: opts.language ?? 'en',
smart_format: opts.smart_format ?? true,
diarize: opts.diarize ?? false,
utterances: opts.utterances ?? false,
paragraphs: opts.paragraphs ?? false,
summarize: opts.summarize ? 'v2' : undefined,
detect_topics: opts.detect_topics ?? false,
sentiment: opts.sentiment ?? false,
intents: opts.intents ?? false,
keywords: opts.keywords,
callback: opts.callback,
}
);
if (error) throw new Error(`Transcription failed: ${error.message}`);
return result;
}
async transcribeFile(filePath: string, opts: TranscribeOptions = {}) {
const audio = readFileSync(filePath);
const mimetype = this.detectMimetype(filePath);
const { result, error } = await this.client.listen.prerecorded.transcribeFile(
audio,
{
model: opts.model ?? 'nova-3',
smart_format: opts.smart_format ?? true,
mimetype,
diarize: opts.diarize ?? false,
utterances: opts.utterances ?? false,
summarize: opts.summarize ? 'v2' : undefined,
detect_topics: opts.detect_topics ?? false,
sentiment: opts.sentiment ?? false,
}
);
if (error) throw new Error(`File transcription failed: ${error.message}`);
return result;
}
private detectMimetype(path: string): string {
const ext = path.split('.').pop()?.toLowerCase();
const map: Record<string, string> = {
wav: 'audio/wav', mp3: 'audio/mpeg', flac: 'audio/flac',
ogg: 'audio/ogg', m4a: 'audio/mp4', webm: 'audio/webm',
};
return map[ext ?? ''] ?? 'audio/wav';
}
}
Step 2: Extract Structured Results
function formatResult(result: any) {
const channel = result.results.channels[0];
const alt = channel.alternatives[0];
return {
transcript: alt.transcript,
confidence: alt.confidence,
words: alt.words?.map((w: any) => ({
word: w.word,
start: w.start,
end: w.end,
confidence: w.confidence,
speaker: w.speaker, // Only if diarize: true
punctuated_word: w.punctuated_word,
})),
// Speaker segments (requires utterances: true + diarize: true)
utterances: result.results.utterances?.map((u: any) => ({
speaker: u.speaker,
text: u.transcript,
start: u.start,
end: u.end,
confidence: u.confidence,
})),
// Audio intelligence results
summary: result.results.summary?.short,
topics: result.results.topics?.segments,
sentiments: result.results.sentiments?.segments,
intents: result.results.intents?.segments,
metadata: {
duration: result.metadata.duration,
channels: result.metadata.channels,
model: result.metadata.model_info,
request_id: result.metadata.request_id,
},
};
}
Step 3: Batch Processing
import pLimit from 'p-limit';
async function batchTranscribe(
files: string[],
opts: TranscribeOptions = {},
concurrency = 5
) {
const transcriber = new DeepgramTranscriber(process.env.DEEPGRAM_API_KEY!);
const limit = pLimit(concurrency);
const results = await Promise.allSettled(
files.map(file =>
limit(async () => {
const result = await transcriber.transcribeFile(file, opts);
console.log(`Done: ${file} (${result.metadata.duration}s)`);
return { file, result: formatResult(result) };
})
)
);
const succeeded = results.filter(r => r.status === 'fulfilled');
const failed = results.filter(r => r.status === 'rejected');
console.log(`Batch complete: ${succeeded.length} ok, ${failed.length} failed`);
return results;
}
Step 4: Async Callback Transcription (Large Files)
// For files >2 hours or when you don't want to hold a connection open,
// use Deepgram's callback feature. Deepgram POSTs results to your URL.
async function submitAsync(audioUrl: string, callbackUrl: string) {
const transcriber = new DeepgramTranscriber(process.env.DEEPGRAM_API_KEY!);
// Deepgram returns a request_id immediately, processes in background
const result = await transcriber.transcribeUrl(audioUrl, {
model: 'nova-3',
diarize: true,
callback: callbackUrl, // Your HTTPS endpoint
});
console.log('Submitted. Request ID:', result.metadata.request_id);
// Deepgram will POST results to callbackUrl when done
// Retries up to 10 times with 30s delay on failure
}
Step 5: Keyword Boosting
// Boost domain-specific terms for higher accuracy
const result = await transcriber.transcribeUrl(audioUrl, {
model: 'nova-3',
keywords: [
'Kubernetes:1.5', // Boost weight 1.0-2.0
'PostgreSQL:1.5',
'microservices:1.3',
],
});
Output
DeepgramTranscriber class with URL and file transcription
- Structured result extraction with word-level timing, speakers, and intelligence
- Batch processing with configurable concurrency via
p-limit
- Async callback pattern for large files
- Keyword boosting for domain vocabulary
Error Handling
| Error |
Cause |
Solution |
400 Bad Request |
Invalid audio format |
Verify file header bytes (WAV: RIFF, MP3: 0xFFF3/0xFFFB) |
413 Payload Too Large |
File exceeds limit |
Use callback URL for async processing |
| Empty transcript |
No speech in audio |
Check audio volume, try alternatives: 3 for confidence |
408 Timeout |
Long file, sync mode |
Switch to callback-based async |
| Low confidence |
Background noise |
Preprocess: ffmpeg -i input.wav -af "highpass=f=200,lowpass=f=3000" clean.wav |
Resources
Next Steps
Proceed to deepgram-core-workflow-b for real-time streaming transcription.
1---2name: deepgram-core-workflow-a3description: |4 Implement production pre-recorded speech-to-text with Deepgram.5 Use when building audio transcription, batch processing,6 or implementing diarization and intelligence features.7 Trigger: "deepgram transcription", "speech to text", "transcribe audio",8 "batch transcription", "deepgram nova", "diarize audio".9allowed-tools: Read, Write, Edit, Bash(npm:*), Bash(pip:*), Grep10version: 1.0.011license: MIT12author: Jeremy Longshore <jeremy@intentsolutions.io>13compatible-with: claude-code, codex, openclaw14tags: [saas, deepgram, voice-ai, transcription, workflow, stt]1516---1718# Deepgram Core Workflow A: Pre-recorded Transcription1920## Overview21Production pre-recorded transcription service using Deepgram's REST API. Covers `transcribeUrl` and `transcribeFile`, speaker diarization, audio intelligence (summarization, topic detection, sentiment, intent), batch processing with concurrency control, and callback-based async transcription for large files.2223## Prerequisites24- `@deepgram/sdk` installed, `DEEPGRAM_API_KEY` configured25- Audio files: WAV, MP3, FLAC, OGG, M4A, or WebM26- For batch: `p-limit` package (`npm install p-limit`)2728## Instructions2930### Step 1: Transcription Service Class3132```typescript33import { createClient, DeepgramClient } from '@deepgram/sdk';34import { readFileSync } from 'fs';3536interface TranscribeOptions {37 model?: 'nova-3' | 'nova-2' | 'nova-2-meeting' | 'nova-2-phonecall' | 'base';38 language?: string;39 diarize?: boolean;40 utterances?: boolean;41 paragraphs?: boolean;42 smart_format?: boolean;43 summarize?: boolean; // Audio intelligence44 detect_topics?: boolean; // Topic detection45 sentiment?: boolean; // Sentiment analysis46 intents?: boolean; // Intent recognition47 keywords?: string[]; // Keyword boosting: ["term:weight"]48 callback?: string; // Async callback URL49}5051class DeepgramTranscriber {52 private client: DeepgramClient;5354 constructor(apiKey: string) {55 this.client = createClient(apiKey);56 }5758 async transcribeUrl(url: string, opts: TranscribeOptions = {}) {59 const { result, error } = await this.client.listen.prerecorded.transcribeUrl(60 { url },61 {62 model: opts.model ?? 'nova-3',63 language: opts.language ?? 'en',64 smart_format: opts.smart_format ?? true,65 diarize: opts.diarize ?? false,66 utterances: opts.utterances ?? false,67 paragraphs: opts.paragraphs ?? false,68 summarize: opts.summarize ? 'v2' : undefined,69 detect_topics: opts.detect_topics ?? false,70 sentiment: opts.sentiment ?? false,71 intents: opts.intents ?? false,72 keywords: opts.keywords,73 callback: opts.callback,74 }75 );76 if (error) throw new Error(`Transcription failed: ${error.message}`);77 return result;78 }7980 async transcribeFile(filePath: string, opts: TranscribeOptions = {}) {81 const audio = readFileSync(filePath);82 const mimetype = this.detectMimetype(filePath);8384 const { result, error } = await this.client.listen.prerecorded.transcribeFile(85 audio,86 {87 model: opts.model ?? 'nova-3',88 smart_format: opts.smart_format ?? true,89 mimetype,90 diarize: opts.diarize ?? false,91 utterances: opts.utterances ?? false,92 summarize: opts.summarize ? 'v2' : undefined,93 detect_topics: opts.detect_topics ?? false,94 sentiment: opts.sentiment ?? false,95 }96 );97 if (error) throw new Error(`File transcription failed: ${error.message}`);98 return result;99 }100101 private detectMimetype(path: string): string {102 const ext = path.split('.').pop()?.toLowerCase();103 const map: Record<string, string> = {104 wav: 'audio/wav', mp3: 'audio/mpeg', flac: 'audio/flac',105 ogg: 'audio/ogg', m4a: 'audio/mp4', webm: 'audio/webm',106 };107 return map[ext ?? ''] ?? 'audio/wav';108 }109}110```111112### Step 2: Extract Structured Results113114```typescript115function formatResult(result: any) {116 const channel = result.results.channels[0];117 const alt = channel.alternatives[0];118119 return {120 transcript: alt.transcript,121 confidence: alt.confidence,122 words: alt.words?.map((w: any) => ({123 word: w.word,124 start: w.start,125 end: w.end,126 confidence: w.confidence,127 speaker: w.speaker, // Only if diarize: true128 punctuated_word: w.punctuated_word,129 })),130 // Speaker segments (requires utterances: true + diarize: true)131 utterances: result.results.utterances?.map((u: any) => ({132 speaker: u.speaker,133 text: u.transcript,134 start: u.start,135 end: u.end,136 confidence: u.confidence,137 })),138 // Audio intelligence results139 summary: result.results.summary?.short,140 topics: result.results.topics?.segments,141 sentiments: result.results.sentiments?.segments,142 intents: result.results.intents?.segments,143 metadata: {144 duration: result.metadata.duration,145 channels: result.metadata.channels,146 model: result.metadata.model_info,147 request_id: result.metadata.request_id,148 },149 };150}151```152153### Step 3: Batch Processing154155```typescript156import pLimit from 'p-limit';157158async function batchTranscribe(159 files: string[],160 opts: TranscribeOptions = {},161 concurrency = 5162) {163 const transcriber = new DeepgramTranscriber(process.env.DEEPGRAM_API_KEY!);164 const limit = pLimit(concurrency);165166 const results = await Promise.allSettled(167 files.map(file =>168 limit(async () => {169 const result = await transcriber.transcribeFile(file, opts);170 console.log(`Done: ${file} (${result.metadata.duration}s)`);171 return { file, result: formatResult(result) };172 })173 )174 );175176 const succeeded = results.filter(r => r.status === 'fulfilled');177 const failed = results.filter(r => r.status === 'rejected');178 console.log(`Batch complete: ${succeeded.length} ok, ${failed.length} failed`);179 return results;180}181```182183### Step 4: Async Callback Transcription (Large Files)184185```typescript186// For files >2 hours or when you don't want to hold a connection open,187// use Deepgram's callback feature. Deepgram POSTs results to your URL.188async function submitAsync(audioUrl: string, callbackUrl: string) {189 const transcriber = new DeepgramTranscriber(process.env.DEEPGRAM_API_KEY!);190191 // Deepgram returns a request_id immediately, processes in background192 const result = await transcriber.transcribeUrl(audioUrl, {193 model: 'nova-3',194 diarize: true,195 callback: callbackUrl, // Your HTTPS endpoint196 });197198 console.log('Submitted. Request ID:', result.metadata.request_id);199 // Deepgram will POST results to callbackUrl when done200 // Retries up to 10 times with 30s delay on failure201}202```203204### Step 5: Keyword Boosting205206```typescript207// Boost domain-specific terms for higher accuracy208const result = await transcriber.transcribeUrl(audioUrl, {209 model: 'nova-3',210 keywords: [211 'Kubernetes:1.5', // Boost weight 1.0-2.0212 'PostgreSQL:1.5',213 'microservices:1.3',214 ],215});216```217218## Output219- `DeepgramTranscriber` class with URL and file transcription220- Structured result extraction with word-level timing, speakers, and intelligence221- Batch processing with configurable concurrency via `p-limit`222- Async callback pattern for large files223- Keyword boosting for domain vocabulary224225## Error Handling226| Error | Cause | Solution |227|-------|-------|----------|228| `400 Bad Request` | Invalid audio format | Verify file header bytes (WAV: `RIFF`, MP3: `0xFFF3/0xFFFB`) |229| `413 Payload Too Large` | File exceeds limit | Use callback URL for async processing |230| Empty transcript | No speech in audio | Check audio volume, try `alternatives: 3` for confidence |231| `408 Timeout` | Long file, sync mode | Switch to callback-based async |232| Low confidence | Background noise | Preprocess: `ffmpeg -i input.wav -af "highpass=f=200,lowpass=f=3000" clean.wav` |233234## Resources235- [Pre-recorded API](https://developers.deepgram.com/docs/pre-recorded-audio)236- [Speaker Diarization](https://developers.deepgram.com/docs/diarization)237- [Audio Intelligence](https://deepgram.com/product/audio-intelligence)238- [Summarization](https://developers.deepgram.com/docs/summarization)239- [Callback Feature](https://developers.deepgram.com/docs/callback)240241## Next Steps242Proceed to `deepgram-core-workflow-b` for real-time streaming transcription.243