shadowfiend / whisper
PHP manager for multiple instance of whispers
Requires
- php: ^8.4
- guzzlehttp/psr7: ^3.0
- psr/http-client: ^1.0
- psr/http-factory: ^1.1
- psr/http-message: ^2.0
Requires (Dev)
- guzzlehttp/guzzle: ^8.0
- phpstan/phpstan: ^2.2
- phpunit/phpunit: ^12.0
Suggests
None
Provides
None
Conflicts
None
Replaces
None
This package is auto-updated.
Last update: 2026-09-10 17:13:29 UTC
README
Whisper is a PHP library for managing multiple audio transcription providers through a single API. It handles provider registration and selection, accepts file paths or custom audio sources The package provides the integration layer rather than a built-in connection to a specific external Whisper service.
Features
- Register and select named transcription providers.
- Transcribe a local file or any custom
AudioSourceInterfaceimplementation. - Work with
Transcriptclass and fields: text, duration, language, metadata, and timed segments. - Whisper service works with psr streams
Requirements
- PHP 8.4 or later
- Composer
Installation
Install the package with Composer:
composer require shadowfiend/whisper
How to use it
Basic usage of your own whisper provider
Register a provider, select it by name, and pass an audio file to transcribe():
<?php use Sf\Whisper\Whisper; $provider = new YourWhisperProvider(); $provider->setOptions([ 'api_key' => env('whisper_service_api_key'), // If your WhisperProvider should us API key 'model' => 'whisper-1', // Whatever else in your options for whisper provider ]); $whisper = new Whisper(); $whisper->addProvider('default', $provider); $transcript = $whisper ->useProvider('default') ->transcribe('/path/to/audio.mp3'); echo $transcript->getText();
A string passed to transcribe() is automatically converted to a FileAudioSource. You can also select a provider through the magic __get method:
$transcript = $whisper->default->transcribe('/path/to/audio.mp3'); // Examples of registered providers, you should add it in your app before through addProvider() $transcript = $whisper->openai->transcribe('/path/to/audio.mp3'); $transcript = $whisper->google->transcribe('/path/to/audio.mp3'); $transcript = $whisper->local->transcribe('/path/to/audio.mp3');
Usage of Transcript
Every provider returns a Transcript. Besides casting it to a string, you can inspect all available result data:
By default Transcript works with fields:
- text
- segments TranscriptSegment[] by default
- duration 0 by default
- language
- metadata
echo (string) $transcript; echo $transcript->getText(); $duration = $transcript->getDuration(); $language = $transcript->getLanguage(); $metadata = $transcript->getMeta(); foreach ($transcript->getSegments() as $segment) { echo sprintf( "[%s - %s] %s\n", $segment->getStart(), $segment->getEnd(), $segment->getText(), ); }
Providers can preserve timing information by adding TranscriptSegment objects:
use Sf\Whisper\Transcript; use Sf\Whisper\TranscriptSegment; $transcript = Transcript::create('Hello world', duration: 1.8) ->addSegment(new TranscriptSegment('Hello', start: 0.0, end: 0.7)) ->addSegment(new TranscriptSegment(' world', start: 0.7, end: 1.8));
How to create custom whisper provider
Create a provider by extending AbstractWhisperProvider and implementing doTranscribe(). The method receives a PSR-7 stream opened at the beginning of the audio.
Note
Do not close stream inside of doTranscribe method because AbstractWhisperProvider always closes the stream after transcription.
<?php use Psr\Http\Message\StreamInterface; use Sf\Whisper\Providers\AbstractWhisperProvider; use Sf\Whisper\Transcript; final class YourWhisperProvider extends AbstractWhisperProvider { protected function doTranscribe(StreamInterface $audio): Transcript { $audioContents = $audio->getContents(); // Send $audioContents to your transcription service and map its response. $response = callYourTranscriptionService($audioContents, $this->options); $transcript = $Transcript::create( text: $response['text'], duration: $response['duration'], ); // If you have segments you can use addSegment() or addSegments() $transcript->setSegments(TranscriptSegment[]); } }
Note
Provider-specific configuration is available through setOptions() and getOptions().
Custom Audio Sources
Implement AudioSourceInterface when audio does not come from a local file. Each extract() call must return a new PSR-7 stream positioned at the beginning.
<?php use GuzzleHttp\Psr7\Utils; use Psr\Http\Message\StreamInterface; use Sf\Whisper\Sources\AudioSourceInterface; final class MemoryAudioSource implements AudioSourceInterface { public function __construct( private readonly string $contents ) { } public function extract(): StreamInterface { return Utils::streamFor($this->contents); } } $transcript = $whisper->transcribe(new MemoryAudioSource($audioContents));
Custom Error Exceptions
WhisperExceptionis thrown when transcription is requested before selecting a provider.TranscribeExceptionwraps any exception thrown by a provider and keeps the original exception asprevious.
Mock Components
MockWhisperProvider and MockAudioSource are included for tests and examples. They exchange predefined JSON data and do not transcribe real audio.
use Sf\Whisper\Providers\MockWhisperProvider; use Sf\Whisper\Sources\MockAudioSource; use Sf\Whisper\Whisper; $whisper = new Whisper(); $whisper->addProvider('mock', new MockWhisperProvider()); $transcript = $whisper->useProvider('mock')->transcribe(new MockAudioSource()); echo $transcript->getText(); // Hello from mock i am mock
Development
Development commands run in Docker through Make:
make install
make install-hooks
make lint
make test
make installbuilds the development image and installs Composer dependencies intovendor/.make install-hooksenables the repository's Git hooks after cloning. The pre-push hook runs the same build, lint, and test checks as CI.make lintruns PHPStan at the maximum level oversrc/andtests/.make testbuilds the image and runs the PHPUnit test suite.
License
This project is available under the MIT License.