# Groq vs OpenAI for Whisper Transcription Setup in Claude-Video

> Discover Groq vs OpenAI for Whisper transcription setup in Claude-Video. Claude-Video prefers Groq for speed and cost, falling back to OpenAI when needed.

- Repository: [bradautomates/claude-video](https://github.com/bradautomates/claude-video)
- Tags: comparison
- Published: 2026-07-29

---

**The Claude-Video watch skill automatically prefers Groq's Whisper API for faster, cheaper transcription while seamlessly falling back to OpenAI when Groq credentials are unavailable.**

The transcription system in the `bradautomates/claude-video` repository implements a backend-agnostic architecture that prioritizes **Groq** for Whisper transcription due to superior speed and cost efficiency, with **OpenAI** serving as a robust fallback. This dual-backend approach is managed entirely within the `/watch` skill, which extracts audio from video content and generates timestamped captions. All configuration is centralized in a user-scoped environment file, allowing seamless switching between providers without code changes.

## How Backend Selection Works

The transcription logic in [`skills/watch/scripts/whisper.py`](https://github.com/bradautomates/claude-video/blob/main/skills/watch/scripts/whisper.py) implements a priority-based detection system that evaluates available credentials before initiating any API calls.

### API Key Discovery

The `load_api_key()` function searches for credentials in a specific order of precedence:

1. **Environment variables** – Checks for `GROQ_API_KEY` first, then `OPENAI_API_KEY`
2. **User configuration file** – Reads from `~/.config/watch/.env` if environment variables are unset

The function returns a tuple containing the backend identifier (`"groq"` or `"openai"`) and the corresponding API key. This discovery mechanism ensures that Groq is always attempted first, aligning with the project's cost-optimization goals.

### Runtime Backend Selection

The `transcribe_video()` function receives optional `backend` and `api_key` parameters. When these are omitted, it invokes `load_api_key()` to determine the available service:

```python
if backend is None or api_key is None:
    detected_backend, detected_key = load_api_key()
    backend = backend or detected_backend
    api_key = api_key or detected_key

```

If neither key is found, the system raises a `SystemExit` with explicit instructions to configure credentials via the setup script:

```text
No Whisper API key available. Set GROQ_API_KEY (preferred) or OPENAI_API_KEY 
in the environment or in ~/.config/watch/.env. 
Run `python3 setup.py` to configure.

```

## Configuring Your API Keys

The [`skills/watch/scripts/setup.py`](https://github.com/bradautomates/claude-video/blob/main/skills/watch/scripts/setup.py) installer automates credential scaffolding and dependency verification.

Running `python3 setup.py` performs three critical tasks:

- **Binary verification** – Confirms `ffmpeg`, `ffprobe`, and `yt-dlp` are installed and accessible
- **Environment creation** – Generates `~/.config/watch/.env` with restrictive permissions (`0600`) containing placeholder keys:

```bash
GROQ_API_KEY=
OPENAI_API_KEY=

```

- **Completion tracking** – Writes `SETUP_COMPLETE=true` to prevent redundant configuration prompts

Users populate this file with either a Groq API key, an OpenAI API key, or both to enable automatic fallback behavior.

## Transcription Pipeline Implementation

The complete workflow from video input to structured captions involves several specialized functions within [`whisper.py`](https://github.com/bradautomates/claude-video/blob/main/whisper.py).

### Audio Extraction and Chunking

The `extract_audio()` function uses **ffmpeg** to convert video streams into mono 16kHz MP3 format. For long videos exceeding the 24 MiB upload limit, the system calculates optimal split points:

- **`plan_chunks()`** – Determines time-based segmentation to keep each part under `MAX_UPLOAD_BYTES`
- **`split_audio()`** – Physically segments the audio file using ffmpeg timestamps
- **`shift_segments()`** – Adjusts timestamps post-transcription to align chunk segments with the original video timeline

### Backend-Specific Endpoints and Models

The implementation defines service-specific constants that map to distinct model versions:

- **Groq**: Endpoint `https://api.groq.com/openai/v1/audio/transcriptions` using model `whisper-large-v3`
- **OpenAI**: Endpoint `https://api.openai.com/v1/audio/transcriptions` using model `whisper-1`

Both services accept identical multipart/form-data payloads, allowing the `_post_whisper()` function to remain provider-agnostic while routing requests to the correct URL.

### Manual Multipart Upload Handling

The `_post_whisper()` function constructs HTTP requests using only Python standard library modules to avoid external dependencies. It manually builds the multipart body and sets a custom `User-Agent` header specifically to bypass Groq's Cloudflare WAF restrictions. Response parsing occurs in `_segments_from_response()`, which normalizes verbose JSON into uniform `{start, end, text}` dictionaries regardless of which backend generated the transcript.

## Forcing a Specific Backend

While automatic selection prefers Groq, the command-line interface in [`watch.py`](https://github.com/bradautomates/claude-video/blob/main/watch.py) allows explicit backend specification:

```bash

# Automatic selection (prefers Groq)

watch https://www.youtube.com/watch?v=example

# Force OpenAI backend

watch https://www.youtube.com/watch?v=example --whisper openai

# Force Groq backend

watch https://www.youtube.com/watch?v=example --whisper groq

```

The argument parser defines this behavior in [`watch.py`](https://github.com/bradautomates/claude-video/blob/main/watch.py):

```python
parser.add_argument(
    "--whisper",
    choices=["groq", "openai"],
    default=None,
    help="Force a specific Whisper backend. Default: prefer Groq, fall back to OpenAI."
)

```

During execution, the skill outputs the selected backend to stderr for transparency:

```text
[watch] extracting audio for Whisper (groq)…
[watch] transcribed 42 segments via groq

```

## Summary

- **Groq is the default** – The `load_api_key()` function in [`whisper.py`](https://github.com/bradautomates/claude-video/blob/main/whisper.py) prioritizes `GROQ_API_KEY` over OpenAI credentials for cost and speed advantages.
- **Seamless fallback** – If Groq keys are absent, the system automatically detects and uses `OPENAI_API_KEY` without requiring code modifications.
- **Configuration location** – All API keys reside in `~/.config/watch/.env`, created with secure permissions by [`setup.py`](https://github.com/bradautomates/claude-video/blob/main/setup.py).
- **Runtime override** – The `--whisper` CLI argument forces a specific backend regardless of automatic detection logic.
- **Unified payload** – Both backends use identical multipart upload logic in `_post_whisper()`, differing only in endpoint URLs and model names.

## Frequently Asked Questions

### Why does the Claude-Video skill prefer Groq over OpenAI for Whisper transcription?

According to the source code comments in [`whisper.py`](https://github.com/bradautomates/claude-video/blob/main/whisper.py), Groq provides significantly faster inference and lower pricing for the Whisper-large-v3 model compared to OpenAI's whisper-1 implementation. The automatic preference ensures users benefit from reduced latency and cost unless they explicitly configure only an OpenAI key.

### Can I use both Groq and OpenAI keys simultaneously in the configuration?

Yes. The `.env` file at `~/.config/watch/.env` supports both `GROQ_API_KEY` and `OPENAI_API_KEY` variables simultaneously. When both are present, the `load_api_key()` function selects Groq by default, but you can force OpenAI usage at runtime with the `--whisper openai` command-line flag.

### What happens if my audio file exceeds the upload size limit?

The `transcribe_video()` function automatically detects file sizes exceeding 24 MiB (`MAX_UPLOAD_BYTES`) and triggers the chunking pipeline. The `plan_chunks()` function calculates time-based splits, `split_audio()` creates temporary audio segments using ffmpeg, and `transcribe_chunks()` processes each part individually before `shift_segments()` reconciles timestamps into a continuous transcript.

### How do I troubleshoot API connection errors with Groq specifically?

The `_post_whisper()` function in [`whisper.py`](https://github.com/bradautomates/claude-video/blob/main/whisper.py) implements a custom `User-Agent` header specifically to circumvent Groq's Cloudflare WAF restrictions. If you encounter connection errors, verify your `GROQ_API_KEY` is correctly set in `~/.config/watch/.env` and ensure the file permissions are `0600`. Run `python3 setup.py` to validate your configuration and check that all required binaries (ffmpeg, ffprobe, yt-dlp) are installed.