Summary
Compact audio player featuring a modern “iMessage-style” voice note pill. Includes waveform visualization, play/pause controls, optional looping, and optional client-side Whisper transcription (inspired by Xenova/whisper-web). State is typically stored as a URL string to the audio file — the transcript is shown in the UI only and is not written back to field state.Basic usage
Dynamic Audio (from State)
Static Audio (Fixed Source)
With client-side transcription
State & validation
Stored value
State is an HTTP(S) or root-relative audio URL string. URLs containing credentials, control characters or unsafe schemes are rejected. This field plays a URL; it does not upload or store the audio file.Validation rules (built-in)
Ensures the state is a valid media URL string.Configuration API
Methods accept closures as well as the displayed values, unless noted.Speech-to-text (Whisper)
Enable optional client-side speech-to-text on anyAudioField that has a playable audio URL. The Quantized switch selects q8 weights; disabling it selects fp32. Inference uses the WASM backend and does not require WebGPU or cross-origin isolation. Transcription runs entirely in the user’s browser via @huggingface/transformers — no server API key, no upload of audio to your backend for STT.
- Transcribe Audio — fetches the audio URL, decodes it with Web Audio, runs Whisper, and shows the result below the player.
- Settings (gear) — submenu for model, language, task, Multilingual, and Quantized toggles (same UX pattern as Xenova/whisper-web).
php artisan fff:whisper:install.
Installing the Whisper runtime
The browser ONNX / WASM runtime (~15 MB) is not included in the Composer package and is not published byphp artisan filament:assets. Only apps that use ->transcription() need it.
Important: filament:assets syncs Flex Fields CSS/JS and small static media (beeps, NPS emoji, etc.). It never installs Whisper. Use the commands below.
One-time install
- Downloads the pinned
@huggingface/transformers4.3.1 browser bundle and its matching ONNX WASM/loader from the jsDelivr npm CDN. - Verifies each file with SHA-256 against the package manifest (
WhisperRuntimeManifest). - Writes them to
public/filament-flex-fields-assets/whisper/4.3.1/. - Writes
public/filament-flex-fields-assets/whisper/4.3.1/.installed.json(version + hashes + timestamp). - Does not install source maps (
.mapfiles are excluded on purpose).
->transcription() as usual.
Inspect status
CI / deploy gate
When your app requires transcription in production, fail the pipeline if the runtime is missing or corrupt:0 = verified. Exit code 1 = missing or invalid (print includes the fix command).
Re-download
Command reference
Files on disk
The field resolves the installed runtime URLs automatically. Each runtime version has its own directory so cached modules and already-open pages cannot mix different runtime versions. The manifest also pins the matching
onnxruntime-web release; its .mjs loader and .wasm file are installed together.
Deploy notes
- Run
fff:whisper:installon each environment that needs transcription (or copy the verifiedpublic/filament-flex-fields-assets/whisper/4.3.1/directory as a build artifact). - Commit the whisper directory only if your deploy strategy requires it; many teams install during CI/CD instead.
- Do not expect
composer installorfilament:assetsalone to restore Whisper after an upgrade. - Upgrading from an older Flex Fields release that bundled Whisper in Composer: remove any stale vendor/public copies from the old layout, then run
fff:whisper:installonce.
Network requirements for install
The install command needs outbound HTTPS to the jsDelivr npm CDN (cdn.jsdelivr.net/npm/@huggingface/transformers@…). Air-gapped hosts must vendor the verified files into public/filament-flex-fields-assets/whisper/4.3.1/ by another channel, then confirm with fff:whisper:install --check. Install access must allow both the pinned @huggingface/transformers and onnxruntime-web npm packages.
Model weights (Hugging Face) are still downloaded in the browser on first Transcribe — that is separate from this artisan install.
Transcript is not field state
The transcript appears in.fff-audio-field__transcript for the current page session. It is not saved to the Eloquent attribute / form state. To persist text, bind a separate field (for example Textarea) or use server-side transcription on VoiceNoteRecorderField via Media OS.
How it works
Progress during the first model load shows the downloading file and percentage (for example
encoder_model.onnx 42%). Model load times out after 10 minutes — enable Quantized or pick a smaller model on slow connections.
Requirements & limitations
Configuration API (transcription)
Methods accept closures as well as the displayed values, unless noted.
Invalid tasks throw
InvalidArgumentException at config evaluation time.
Global defaults (config/filament-flex-fields.php)
These config keys apply when the matching field method is not set:
->transcription() without extra methods:
Model catalog & settings toggles
Models and filtering follow whisper-web’s AudioManager:
The settings menu lists models with approximate download size, for example
Xenova/whisper-tiny (41 MB).
The Language submenu exposes the full Whisper ISO 639-1 catalog (90+ languages plus Auto detect), aligned with whisper-web.
Real-world examples
Polish voice note with fixed language
English-only, quantized distil model
Transcribe button only (no user-facing settings)
Translate foreign audio to English
Troubleshooting
User-facing copy is translatable under
filament-flex-fields::default.audio.transcription_* in resources/lang.
Real-world examples
Post-Recording Preview
Fixed Demo Track
Playground
/admin/flex-fields/audio-field
Two sections:
See Playground for setup.
Related components
CSS classes (reference)
Keyboard, layout and resource use
Focus the waveform and use Left/Right to seek by five seconds, Home for the beginning and End for the end. Seeking follows RTL direction. The play button supports normal button keyboard activation. Read-only and disabled fields block interaction. The compact player keeps its existing appearance in all three sizes. Waveform bar count adapts to the available width. Providewaveform() when you already have peaks to avoid fetching audio for analysis. Without custom peaks, the initial display uses a deterministic waveform; real analysis is lazy and never delays playback. Automatic analysis skips tracks whose known duration exceeds ten minutes and limits downloads to 32 MB.
Only playing audio runs a progress animation. Removing the field stops playback and cancels owned requests, gestures, observers and timers. Inactive tabs and modals use the FLEX activation lifecycle; merely scrolling the field out of view does not stop it.
Whisper is optional. Changing the source or removing the field cancels its pending fetch and discards obsolete results. An already running native model inference may continue internally; it cannot update a disposed field. Model weights remain subject to browser caching and memory limits. For long recordings or centralized processing, use a server transcription provider with Voice Note Recorder instead.