A breathtaking dance of colors unfolds as the sun bids farewell to the sky and river, casting a spellbinding glow that whispers of tranquility and dreams. Witness the magic of a sunset-kissed horizon, where nature paints a masterpiece of serene serenity.

ext-whisper: PHP-Native Audio Transcription

A huge amount of organizational knowledge isn’t written down — it’s spoken. Podcast back catalogs, recorded meetings, webinars, support calls, sermon archives, conference talks. All of it is invisible to search, because search engines only read text.

ext-whisper fixes that for PHP applications.

It’s a PHP 8.3+ extension that runs OpenAI’s Whisper speech-to-text models inside the PHP process via whisper.cpp (through the whisper-rs Rust bindings) — the same architecture as ext-infer, pointed at a different model family. Audio goes in, text and timestamped segments come out. Nothing touches a network.

The shape of the API

Load a GGUF-format Whisper model, hand it 16kHz mono WAV audio, get a transcript:

<?php
use Displace\Whisper\Model;

$model  = Model::load('models/ggml-base.en.gguf');
$result = $model->transcribe('episode-042.wav');

echo $result->text();                  // full transcript

foreach ($result->segments() as $segment) {
    printf("[%.1fs – %.1fs] %s\n",
        $segment['start'],
        $segment['end'],
        $segment['text'],
    );
}

A flat transcript makes audio searchable; timestamped segments make it navigable. When search matches a segment, you know the exact offset — so the result can deep-link to 14:32 of the recording instead of dumping the user at the start of an hour-long file. Segments are also natural chunk boundaries for generating embeddings.

The 16kHz contract

v0.1 accepts exactly one input format: 16kHz, mono, 16-bit WAV — which is what Whisper models consume natively. Rather than bundling a half-baked audio decoder, the extension documents a one-liner to handle converting other audio formats.

ffmpeg -i episode-042.mp3 -ar 16000 -ac 1 -c:a pcm_s16le episode-042.wav

ffmpeg already decodes every format on earth. The contract-first v0.1 of ext-whisper keeps the extension small and the behavior predictable.

Model selection

Whisper comes in sizes from tiny (~75 MB) through large (~3 GB), with English-only variants that outperform multilingual siblings at the same size. Practical guidance:

  • base.en — fast, light, solid for clear single-speaker audio. Start here.
  • small.en / medium.en — the accuracy sweet spot for podcasts and recorded talks.
  • large — for multilingual audio or difficult recordings, when you can afford the compute.

Transcription is batch-natured — a queued worker chewing through an archive overnight is the natural deployment shape, and it’s the workload where local processing crushes cloud economics. Per-minute transcription pricing on an archive of hundreds of hours is real money; a local model is basically just the cost of electricity you were already paying for.

For audio with privacy weight — internal meetings, support calls, anything under attorney-client or healthcare constraints — local-only processing isn’t just a nice-to-have.

The stack is complete

With ext-whisper, the three native pillars for local AI are in place:

  • ext-infer — generation and embeddings
  • ext-turbovec — vector indexing and search
  • ext-whisper — speech to text

Transcribe → embed → index → search → generate, every stage in-process, every byte on hardware you control. What’s missing is the connective tissue — the interfaces that let these pieces compose with each other and with the wider PHP ecosystem without coupling anyone to anyone.

We’ll tackle that tomorrow.