Skip to content
Back to skills

Deepgram Core Workflow A

ASecurity

'Implement production pre-recorded speech-to-text with Deepgram.

  • 2,719 stars
  • 0 votes
  • 0 copies
  • 1 view
  • Added September 21, 2026
ai-agentstypescriptbashsqlkubernetesapi

Works with

  • claude code
  • cli
  • api

Security analysis

A92/100
  • mediumInstalls packages at runtime which could introduce malicious dependencies

Pro scans all 2 files and shows the line behind each finding

Scanned September 21, 2026

npx -y skills add jeremylongshore/claude-code-plugins-plus --skill deepgram-core-workflow-a --agent claude-code

Installs into .claude/skills of the current project.

Are you the author of Deepgram Core Workflow A?

Add the live security badge to your README. It updates with every re-scan.

Security grade badge for Deepgram Core Workflow A
[![Security: A — Skills Directory](https://www.skillsdirectory.com/api/skills/jeremylongshore-deepgram-core-workflow-a-a5d5abfe/badge)](https://www.skillsdirectory.com/skills/jeremylongshore-deepgram-core-workflow-a-a5d5abfe)

More formats (shields.io, HTML) on the badges page. Keep it an A: scan every change in CI with Pro.

Download with Pro
SKILL.md
---
name: deepgram-core-workflow-a
description: 'Implement production pre-recorded speech-to-text with Deepgram.

  Use when building audio transcription, batch processing,

  or implementing diarization and intelligence features.

  Trigger: "deepgram transcription", "speech to text", "transcribe audio",

  "batch transcription", "deepgram nova", "diarize audio".

  '
allowed-tools: Read, Write, Edit, Bash(npm:*), Bash(pip:*), Grep
version: 1.13.0
license: MIT
author: Jeremy Longshore <jeremy@intentsolutions.io>
tags:
- saas
- deepgram
- voice-ai
- transcription
- workflow
- stt
compatibility: Designed for Claude Code
---
# Deepgram Core Workflow A: Pre-recorded Transcription

## Examples

Upload a short synthetic or licensed audio fixture to the development workflow, validate transcript format, timestamps, language/model choice, and error handling, then remove the artifact according to retention policy. Do not use customer recordings for a tutorial or log raw transcript text when a correlation ID and aggregate result suffice.

## 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

```typescript
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

```typescript
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

```typescript
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)

```typescript
// 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

```typescript
// 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

- [Pre-recorded API](https://developers.deepgram.com/docs/pre-recorded-audio)
- [Speaker Diarization](https://developers.deepgram.com/docs/diarization)
- [Audio Intelligence](https://deepgram.com/product/audio-intelligence)
- [Summarization](https://developers.deepgram.com/docs/summarization)
- [Callback Feature](https://developers.deepgram.com/docs/callback)

## Next Steps

Proceed to `deepgram-core-workflow-b` for real-time streaming transcription.

Files in this skill

  • SKILL.md8.5 KB
  • references/implementation.md5.5 KB

Attribution

Is this your skill, or is something wrong with this listing? Request removal or report an issue. Author removals are honored within 72 hours.

Comments

Loading comments…

Newsletter

Get the weekly list of safe new skills, and the ones we pulled.