Looking to hire Laravel developers? Try LaraJobs
This package is not available.

assemblyai-laravel maintained by alex-volga

Description
AssemblyAI Speech-to-Text and Audio Intelligence SDK integration for Laravel (v11, v12, v13)
Last update
2026/10/21 09:32 (dev-main)
License
Downloads
32

Comments
comments powered by Disqus

AssemblyAI Laravel

Latest Version on Packagist GitHub Tests Action Status Total Downloads License

A clean, modern Laravel integration for the AssemblyAI PHP SDK. Provides seamless support for speech-to-text, audio intelligence (summarization, sentiment analysis, entity detection, PII redaction), LeMUR LLM queries, real-time streaming tokens, webhook handling, and comprehensive testing fakes.

Designed for Laravel 11, 12, and 13 on PHP 8.3+.


Features

  • Laravel Package Discovery: Automatically registers the Service Provider and Facade.
  • Convenient Facade: AssemblyAI::transcribe(...), AssemblyAI::upload(...), AssemblyAI::lemur(), etc.
  • Dependency Injection: Type-hint AssemblyAI\AssemblyAIClient in controllers, jobs, and services.
  • Multiple Connections / Profiles: Support for default, EU data residency endpoint, or custom on-the-fly clients.
  • Built-in Webhook Handling: Dedicated route macro and events (TranscriptCompleted, TranscriptError) with secret header validation.
  • Testing Fake: Mock transcriptions and uploads with expressive assertions (AssemblyAI::fake(), assertTranscribed(), assertUploaded()).
  • Strictly Typed: Fully typed with strict types enabled and PHPStan Level 8 compliant.

Requirements

  • PHP: ^8.3 || ^8.4 || ^8.5
  • Laravel: ^11.0 || ^12.0 || ^13.0

Installation

Install the package via Composer:

composer require alex-volga/assemblyai-laravel

Publish the configuration file:

php artisan vendor:publish --tag=assemblyai-config

This will create config/assemblyai.php in your application.


Configuration

Set your AssemblyAI API key in your .env file:

ASSEMBLYAI_API_KEY=your_assemblyai_api_key_here

# Optional configuration
ASSEMBLYAI_BASE_URL=https://api.assemblyai.com # Use https://api.eu.assemblyai.com for EU region
ASSEMBLYAI_TIMEOUT=60.0
ASSEMBLYAI_POLL_INTERVAL=3
ASSEMBLYAI_POLL_TIMEOUT=300
ASSEMBLYAI_WEBHOOK_HEADER=X-Webhook-Secret
ASSEMBLYAI_WEBHOOK_SECRET=your_custom_webhook_secret

Configuration Options (config/assemblyai.php)

return [
    'api_key' => env('ASSEMBLYAI_API_KEY'),
    'base_url' => env('ASSEMBLYAI_BASE_URL', \AssemblyAI\Config::DEFAULT_BASE_URL),
    'timeout' => (float) env('ASSEMBLYAI_TIMEOUT', 60.0),
    'poll_interval' => (int) env('ASSEMBLYAI_POLL_INTERVAL', 3),
    'poll_timeout' => (int) env('ASSEMBLYAI_POLL_TIMEOUT', 300),
    'headers' => [],

    'webhook' => [
        'header' => env('ASSEMBLYAI_WEBHOOK_HEADER', 'X-Webhook-Secret'),
        'secret' => env('ASSEMBLYAI_WEBHOOK_SECRET'),
    ],
];

Basic Usage

1. Transcribe Audio (Synchronous / Polling)

You can pass a remote URL, a local file path, or a file stream. AssemblyAI::transcribe() will upload the file if needed, poll until processing completes, and return a strongly-typed Transcript object:

use AssemblyAI\Laravel\Facades\AssemblyAI;

// Transcribe from a public URL
$transcript = AssemblyAI::transcribe('https://storage.googleapis.com/aai-web-samples/gettysburg.wav');

echo $transcript->id;
echo $transcript->text;

With custom transcription options:

use AssemblyAI\Laravel\Facades\AssemblyAI;
use AssemblyAI\Enums\SpeechModel;
use AssemblyAI\Enums\SummaryType;

$transcript = AssemblyAI::transcribe(
    audio: storage_path('app/podcasts/episode-1.mp3'),
    params: [
        'speaker_labels' => true,
        'speakers_expected' => 2,
        'auto_chapters' => true,
        'summary_type' => SummaryType::Bullets,
    ],
    onPoll: function ($pollingTranscript) {
        logger()->info("Transcription status: {$pollingTranscript->status->value}");
    }
);

// Access utterances and chapters
foreach ($transcript->utterances as $utterance) {
    echo "Speaker {$utterance->speaker}: {$utterance->text}\n";
}

2. Dependency Injection

You can inject AssemblyAI\AssemblyAIClient directly into controllers, queued jobs, or services:

namespace App\Http\Controllers;

use AssemblyAI\AssemblyAIClient;
use Illuminate\Http\JsonResponse;
use Illuminate\Http\Request;

class PodcastController extends Controller
{
    public function transcribe(Request $request, AssemblyAIClient $client): JsonResponse
    {
        $transcript = $client->transcribe($request->input('audio_url'));

        return response()->json([
            'id' => $transcript->id,
            'text' => $transcript->text,
        ]);
    }
}

3. File Uploads

Upload local files to AssemblyAI's secure CDN before creating transcriptions:

use AssemblyAI\Laravel\Facades\AssemblyAI;

$uploadUrl = AssemblyAI::upload(storage_path('app/meeting.mp3'));
// Returns: https://cdn.assemblyai.com/upload/...

4. Asynchronous Transcriptions & Webhooks

When transcribing long files, submit a background transcription job with a webhook callback:

use AssemblyAI\Laravel\Facades\AssemblyAI;

$transcript = AssemblyAI::transcripts()->submit([
    'audio_url' => 'https://example.com/recording.mp3',
    'webhook_url' => route('assemblyai.webhook'),
    'webhook_auth_header_name' => config('assemblyai.webhook.header'),
    'webhook_auth_header_value' => config('assemblyai.webhook.secret'),
]);

Register the Webhook Route

In routes/web.php or routes/api.php:

use Illuminate\Support\Facades\Route;

// Registers POST /assemblyai/webhook (named 'assemblyai.webhook')
Route::assemblyAiWebhooks();

// Or define a custom path:
Route::assemblyAiWebhooks('api/v1/assemblyai/callback');

Note: If you register the route in routes/web.php, remember to exclude /assemblyai/webhook from CSRF protection in bootstrap/app.php:

->withMiddleware(function (Middleware $middleware) {
    $middleware->validateCsrfTokens(except: [
        'assemblyai/webhook',
    ]);
})

Listen for Webhook Events

When AssemblyAI notifies your endpoint, the package validates the secret header and automatically dispatches one of the following events:

  • AssemblyAI\Laravel\Events\TranscriptCompleted
  • AssemblyAI\Laravel\Events\TranscriptError

Example listener:

namespace App\Listeners;

use AssemblyAI\Laravel\Events\TranscriptCompleted;
use AssemblyAI\Laravel\Facades\AssemblyAI;

class HandleCompletedTranscript
{
    public function handle(TranscriptCompleted $event): void
    {
        $transcriptId = $event->transcriptId;

        // Fetch full transcript details
        $transcript = AssemblyAI::transcripts()->get($transcriptId);

        // Process transcript (save to database, notify users, etc.)
    }
}

Register the listener in app/Providers/AppServiceProvider.php (or EventServiceProvider):

use App\Listeners\HandleCompletedTranscript;
use AssemblyAI\Laravel\Events\TranscriptCompleted;
use Illuminate\Support\Facades\Event;

public function boot(): void
{
    Event::listen(TranscriptCompleted::class, HandleCompletedTranscript::class);
}

5. LeMUR (LLM Intelligence over Audio)

Apply Large Language Models directly to your transcripts:

use AssemblyAI\Laravel\Facades\AssemblyAI;
use AssemblyAI\Enums\LemurModel;

// Ask questions about the transcript
$qna = AssemblyAI::lemur()->questionAnswer([
    'transcript_ids' => [$transcript->id],
    'questions' => [
        ['question' => 'What was the main outcome of the meeting?'],
        ['question' => 'Who was assigned the follow-up tasks?'],
    ],
    'final_model' => LemurModel::Claude3_5_Sonnet,
]);

// Extract action items
$actionItems = AssemblyAI::lemur()->actionItems([
    'transcript_ids' => [$transcript->id],
]);

6. Multiple Connections (e.g. EU Region)

Define additional connections in config/assemblyai.php:

'connections' => [
    'eu' => [
        'api_key' => env('ASSEMBLYAI_EU_API_KEY'),
        'base_url' => \AssemblyAI\Config::EU_BASE_URL,
    ],
],

Switch connections at runtime:

use AssemblyAI\Laravel\Facades\AssemblyAI;

$euClient = AssemblyAI::connection('eu');
$transcript = $euClient->transcribe('https://example.com/audio.mp3');

Or build an on-the-fly client with custom configuration:

$client = AssemblyAI::build([
    'api_key' => 'temporary-api-key',
    'timeout' => 120.0,
]);

Testing & Mocking (AssemblyAI::fake())

This package includes a first-class test fake so you can test your features without making real HTTP requests or spending API credits:

use AssemblyAI\Laravel\Facades\AssemblyAI;
use AssemblyAI\ValueObjects\Transcript;

public function test_it_transcribes_audio(): void
{
    // Fake AssemblyAI
    AssemblyAI::fake();

    // Perform application logic (e.g. call a controller, dispatch a job)
    $response = $this->postJson('/api/transcribe', [
        'url' => 'https://example.com/audio.mp3',
    ]);

    $response->assertOk();

    // Assert that transcription was requested
    AssemblyAI::assertTranscribed('https://example.com/audio.mp3');

    // Or assert with a custom callback
    AssemblyAI::assertTranscribed(function ($audio, $params) {
        return $audio === 'https://example.com/audio.mp3'
            && ($params['speaker_labels'] ?? false) === true;
    });

    // Assert other files were not transcribed
    AssemblyAI::assertNotTranscribed('https://example.com/other.mp3');
}

Pre-queuing Mock Responses

$customTranscript = Transcript::fromArray([
    'id' => 'custom-id-123',
    'status' => 'completed',
    'audio_url' => 'https://example.com/audio.mp3',
    'text' => 'Expected mock transcription text.',
]);

AssemblyAI::fake([$customTranscript]);

Testing

Run unit and feature tests:

composer test

Run static analysis with PHPStan:

composer analyse

Changelog

Please see CHANGELOG.md for more information on what has changed recently.


Contributing

Please see CONTRIBUTING.md for details.


Security Vulnerabilities

Please review SECURITY.md on how to report security vulnerabilities.


Credits


License

The MIT License (MIT). Please see License File for more information.