Groq vs OpenAI Whisper Integration: A Technical Comparison in claude-video

The claude-video repository's watch skill supports both Groq and OpenAI Whisper backends with identical chunking, retry, and parsing logic, differing only in endpoint URLs, model identifiers, API key environment variables, and a custom User-Agent header required for Groq's Cloudflare edge.

The watch skill in bradautomates/claude-video provides flexible audio transcription by abstracting Whisper access behind a unified interface. Understanding the Groq vs OpenAI Whisper implementation differences helps developers optimize for latency, cost, and availability when processing video content.

Endpoint and Model Configuration Differences

The primary distinction between backends lives in the ENDPOINTS dictionary defined at the top of skills/watch/scripts/whisper.py (lines 29-34):

ENDPOINTS = {
    "groq": {
        "url": "https://api.groq.com/openai/v1/audio/transcriptions",
        "model": "whisper-large-v3",  # Largest Groq-hosted model

    },
    "openai": {
        "url": "https://api.openai.com/v1/audio/transcriptions",
        "model": "whisper-1",  # Default OpenAI model

    },
}

Groq routes to whisper-large-v3 on Groq's LPU infrastructure, while OpenAI uses the standard whisper-1 model. Both expose OpenAI-compatible HTTP endpoints, enabling the shared client implementation.

API Key Resolution Priority

The load_api_key() function (lines 65-71 and 98-108) implements a preference-based fallback system:

  1. GROQ_API_KEY — checked first regardless of which backend is requested
  2. OPENAI_API_KEY — used as secondary fallback

This design allows seamless switching without manual key management. When running:

watch https://youtu.be/xyz

The skill auto-selects Groq if GROQ_API_KEY is present, otherwise falls back to OpenAI.

To force a specific backend from the CLI:

watch https://youtu.be/xyz --whisper openai

Store keys in ~/.config/watch/.env:

GROQ_API_KEY="your-groq-key-here"
OPENAI_API_KEY="your-openai-key-here"

Network-Level Differences: User-Agent Handling

The _post_whisper() function (lines 45-51) adds backend-specific headers:

headers = {
    "Authorization": f"Bearer {api_key}",
    # Custom UA required for Groq's Cloudflare edge

    "User-Agent": "watch-skill/1.0 (+claude-code; python-urllib)",
}

Groq's Cloudflare front-end blocks generic Python urllib User-Agents, necessitating this custom identifier. The same header is sent to both services, but it only affects request success with Groq. OpenAI accepts the standard urllib identity without issue.

Shared Implementation: Chunking, Retries, and Parsing

Beyond the four backend-specific differences (endpoint, model, API key variable, User-Agent), the codebase treats both services identically.

Audio Preparation

The extract_audio() function generates a mono 16 kHz MP3 that satisfies both services' 25 MiB upload limit. No backend-specific encoding logic exists.

Intelligent Chunking

plan_chunks() in _post_whisper() (line 58) calculates time-aligned splits using MAX_UPLOAD_BYTES when audio exceeds the limit. Both services receive identically-sized chunks.

Retry Logic

HTTP 429 rate-limit responses trigger identical exponential backoff for both backends (lines 71-78):

if resp.status == 429 and attempt < MAX_429_RETRIES:
    time.sleep(2 ** attempt)  # Exponential backoff

    continue

The MAX_429_RETRIES constant applies universally—no service-specific tuning is implemented.

Response Normalization

_segments_from_response() (line 82) parses the JSON segments array into a unified format used throughout the pipeline:

{"start": 0.0, "end": 5.32, "text": "Transcribed content..."}

This abstraction allows downstream components to remain backend-agnostic.

Practical Usage Examples

Run transcription with auto-selected backend:

python3 -m skills.watch.scripts.whisper /path/to/video.mp4

Force OpenAI explicitly:

watch https://youtu.be/xyz --whisper openai

Use Groq via environment variable:

export GROQ_API_KEY="your-groq-key-here"
watch https://youtu.be/xyz

Key Source Files

File Responsibility
skills/watch/scripts/whisper.py Core transcription logic: endpoints, models, API keys, multipart upload, retries
skills/watch/scripts/watch.py Entry point that orchestrates transcribe_video() and backend selection
skills/watch/scripts/config.py User configuration loading for .env file location
skills/watch/scripts/setup.py Generates default .env templates for new users

Summary

  • Groq vs OpenAI Whisper integration in claude-video differs in four specific areas: endpoint URL, model name (whisper-large-v3 vs whisper-1), preferred API key environment variable, and a custom User-Agent header required for Groq's Cloudflare edge
  • All other logic is shared: audio extraction, chunked upload planning, multipart request construction, rate-limit retry handling, and response segment parsing
  • API key resolution prefers Groq: GROQ_API_KEY is checked before OPENAI_API_KEY regardless of requested backend
  • The custom User-Agent header (watch-skill/1.0 (+claude-code; python-urllib)) exists solely to satisfy Groq's WAF rules and is harmless to OpenAI
  • Backend switching is transparent at the CLI level via --whisper groq|openai with no code changes required

Frequently Asked Questions

How do I switch between Groq and OpenAI Whisper backends?

Use the --whisper flag with the watch command: watch URL --whisper openai forces OpenAI, while omitting the flag auto-selects based on available API keys. The GROQ_API_KEY environment variable takes precedence if present.

Why does the Groq backend need a custom User-Agent header?

Groq's API sits behind Cloudflare's WAF, which blocks requests from generic python-urllib User-Agents. The _post_whisper() function in skills/watch/scripts/whisper.py (lines 45-51) sends watch-skill/1.0 (+claude-code; python-urllib) to bypass this restriction. OpenAI does not enforce this rule.

Do both backends support the same audio formats and limits?

Yes. The extract_audio() function produces identical mono 16 kHz MP3 output for both services, and both respect the same 25 MiB per-request limit handled by plan_chunks(). The chunking, retry, and response parsing code is fully shared between backends.

Which Whisper model does each backend use?

According to skills/watch/scripts/whisper.py lines 30-33, Groq uses whisper-large-v3 (its largest hosted model) while OpenAI uses whisper-1 (the default API model). These are hardcoded in the ENDPOINTS dictionary and cannot be overridden without modifying the source.

Have a question about this repo?

These articles cover the highlights, but your codebase questions are specific. Give your agent direct access to the source. Share this with your agent to get started:

Share the following with your agent to get started:
curl -s "https://instagit.com/install.md"

Works with
Claude Codex Cursor VS Code OpenClaw Any MCP Client

Maintain an open-source project? Get it listed too →