flutter_whisper_ggml 0.0.1 copy "flutter_whisper_ggml: ^0.0.1" to clipboard
flutter_whisper_ggml: ^0.0.1 copied to clipboard

Offline speech recognition for Flutter powered by whisper.cpp.

flutter_whisper_ggml #

CI

Cross-platform, offline speech recognition for Flutter powered by a bundled and pinned whisper.cpp v1.9.2 runtime.

The plugin runs inference locally, accepts WAV audio, reports progress and live segments, and exports timestamped results as text, JSON or SRT. Native platforms use Dart FFI; Web runs whisper.cpp in a Web Worker through WebAssembly.

Highlights:

  • Android, iOS, Linux, macOS, Web and Windows support;
  • automatic download and verified cache for 34 official GGML models;
  • manual model paths, application assets, HTTP URLs and browser file selection;
  • CPU plus optional CUDA/Vulkan acceleration on supported desktop builds;
  • language detection, translation, greedy/beam decoding, prompts, timestamps, VAD controls, cancellation and live segments;
  • no FFmpeg or model binaries bundled into the package.

0.0.1 is a beta release. The public API may change before 1.0.0.

Contents #

Platform support #

Platform Runtime Acceleration Current validation
Windows x64 Dart FFI CPU, CUDA or Vulkan CI build and manual use
Linux x64 Dart FFI CPU or Vulkan CPU/Vulkan CI builds
Android 24+ Dart FFI/NDK CPU/NEON, ARM64 and x86_64 Release CI build
iOS 13+ Dart FFI/CocoaPods CPU + Accelerate Simulator and unsigned ARM64 CI builds
macOS 10.15+ Dart FFI/CocoaPods CPU + Accelerate Release CI build
Web Web Worker + WebAssembly CPU SIMD/pthreads CI build and manual use

iOS and macOS compile in CI but have not yet been validated on physical Apple hardware. Metal, Android Vulkan and WebGPU are not enabled. CUDA and Vulkan only appear in device enumeration when they were compiled into the native library.

Quick start #

1. Install #

dependencies:
  flutter_whisper_ggml: ^0.0.1
import 'package:flutter_whisper_ggml/flutter_whisper.dart';

The package already contains whisper.cpp. Consumers do not need a separate source checkout or system installation.

2. Allow automatic downloads on Android #

Only applications that call FlutterWhisper.loadModel or WhisperModelManager.prepare need network access. Add this outside the <application> element in android/app/src/main/AndroidManifest.xml:

<uses-permission android:name="android.permission.INTERNET" />

Applications that provide a local model can omit this permission.

3. Download, load and transcribe #

final whisper = await FlutterWhisper.loadModel(
  model: WhisperModels.smallQ5_1,
  config: const WhisperModelConfig(useGpu: false),
  onDownloadProgress: (progress) {
    print('download: ${progress.percent}%');
  },
  onModelProgress: (progress) {
    print('model: $progress%');
  },
);

try {
  final result = await whisper.transcribeFile(
    '/path/to/speech.wav',
    config: const WhisperTranscribeConfig(
      language: 'pt',
      threads: 4,
    ),
    onProgress: (progress) => print('inference: $progress%'),
    onSegment: (segment) => print(segment.text),
  );

  print(result.text);
  print(result.toSrt());
  print(result.toJsonString());
} finally {
  await whisper.dispose();
}

The first native call downloads and verifies the model. Later calls reuse the cache and inference is fully offline. On Web, reuse depends on normal browser HTTP caching.

Load an existing model #

final whisper = await FlutterWhisper.load(
  modelPath: '/path/to/ggml-small-q5_1.bin',
  config: const WhisperModelConfig(
    useGpu: true,
    flashAttention: true,
  ),
  onModelProgress: (progress) => print('model: $progress%'),
);

One FlutterWhisper instance owns one model context. Calls on the same instance are serialized. Always call dispose() when the session is no longer needed.

Audio input #

The plugin intentionally accepts WAV only. The most predictable input is:

  • mono;
  • 16 kHz;
  • signed 16-bit PCM;
  • speech normalized without clipping.

The Dart decoder also reads supported PCM/Float WAV variants, mixes multiple channels to mono and resamples to 16 kHz. Canonical PCM16 remains recommended because it removes ambiguity before inference.

MP3, AAC, M4A, MP4 and other compressed containers are outside this package. Convert them in the application before calling transcribeFile. The full example demonstrates optional FFmpeg conversion without making FFmpeg a plugin dependency.

Already decoded mono 16 kHz samples can be passed directly:

final result = await whisper.transcribe(
  samples,
  config: const WhisperTranscribeConfig(language: 'auto'),
);

Models #

Models are not included in the package archive. WhisperModels.values contains all 34 variants supported by the bundled upstream download scripts.

Choose a multilingual model — one without .en — for Brazilian Portuguese.

Goal Suggested model Approximate download
Smoke test or very constrained device tiny-q5_1 31 MiB
Lightweight mobile use base-q5_1 57 MiB
Balanced Portuguese/mobile/desktop small-q5_1 181 MiB
Strong desktop quality and speed large-v3-turbo-q5_0 547 MiB
Maximum available quality large-v3 2.88 GiB

.en models recognize English only. q5 and q8 variants are quantized: they use less storage and memory, with a possible accuracy tradeoff. Large models can exceed browser, mobile or GPU memory limits even when the download succeeds.

Automatic cache #

final modelPath = await WhisperModelManager.prepare(
  WhisperModels.largeV3TurboQ5_0,
  directoryPath: optionalModelsDirectory,
  forceDownload: false,
  onProgress: (progress) {
    print('${progress.receivedBytes}/${progress.totalBytes}');
  },
);

On native platforms, the default location is a flutter_whisper_ggml/models folder inside the application-support directory. Downloads:

  • stream directly to disk instead of buffering the model in memory;
  • use a temporary .part file;
  • verify exact size and SHA-256;
  • retain a .sha256 cache marker after successful verification;
  • preserve an existing model if a replacement download fails.

Set modelDirectory/directoryPath when the application needs to own the cache location. Set forceDownload: true to replace a cached copy. Cache deletion is currently application-managed.

On Web, prepare returns the official HTTPS URL. The Web Worker downloads the model during loadModel, and onModelProgress reports that operation.

Files named for-tests-* in upstream whisper.cpp contain headers but no model weights. They cannot transcribe audio and are rejected by the native loader.

All model downloads #

Links and exact catalog metadata come from the model repositories used by the whisper.cpp v1.9.2 download scripts.

Model Size Variant
tiny 74 MiB Multilingual
tiny-q5_1 31 MiB Multilingual, quantized
tiny-q8_0 42 MiB Multilingual, quantized
tiny.en 74 MiB English only
tiny.en-q5_1 31 MiB English only, quantized
tiny.en-q8_0 42 MiB English only, quantized
base 141 MiB Multilingual
base-q5_1 57 MiB Multilingual, quantized
base-q8_0 78 MiB Multilingual, quantized
base.en 141 MiB English only
base.en-q5_1 57 MiB English only, quantized
base.en-q8_0 78 MiB English only, quantized
small 465 MiB Multilingual
small-q5_1 181 MiB Multilingual, quantized
small-q8_0 252 MiB Multilingual, quantized
small.en 465 MiB English only
small.en-q5_1 181 MiB English only, quantized
small.en-q8_0 252 MiB English only, quantized
small.en-tdrz 465 MiB English, experimental speaker turns
medium 1.43 GiB Multilingual
medium-q5_0 514 MiB Multilingual, quantized
medium-q8_0 785 MiB Multilingual, quantized
medium.en 1.43 GiB English only
medium.en-q5_0 514 MiB English only, quantized
medium.en-q8_0 785 MiB English only, quantized
large-v1 2.88 GiB Multilingual
large-v2 2.88 GiB Multilingual
large-v2-q5_0 1.01 GiB Multilingual, quantized
large-v2-q8_0 1.54 GiB Multilingual, quantized
large-v3 2.88 GiB Multilingual, highest quality
large-v3-q5_0 1.01 GiB Multilingual, quantized
large-v3-turbo 1.51 GiB Multilingual, faster large model
large-v3-turbo-q5_0 547 MiB Multilingual, recommended desktop balance
large-v3-turbo-q8_0 834 MiB Multilingual, higher-precision quantization

Transcription controls #

WhisperTranscribeConfig exposes:

  • automatic or explicit language;
  • translation to English;
  • greedy or beam-search sampling;
  • thread count, offset and duration;
  • initial prompt and context control;
  • token timestamps and segment/token length controls;
  • temperature fallback and probability thresholds;
  • TinyDiarize and Silero VAD parameters.

Example with beam search and live segments:

final result = await whisper.transcribeFile(
  wavPath,
  config: const WhisperTranscribeConfig(
    language: 'auto',
    strategy: WhisperSamplingStrategy.beamSearch,
    beamSize: 5,
    tokenTimestamps: true,
    splitOnWord: true,
  ),
  onProgress: (progress) => updateProgress(progress / 100),
  onSegment: appendLiveSegment,
);

Cancellation is cooperative:

whisper.cancel();

The active operation finishes after native inference reaches a cancellation checkpoint. Disposing a session waits for its queued work.

Silero VAD requires a separate compatible VAD model path in WhisperVadConfig; the speech-model catalog does not download VAD models automatically.

Device and GPU selection #

final devices = FlutterWhisper.availableDevices;

for (final device in devices) {
  print('${device.name}: ${device.type}');
  print('memory: ${device.freeMemory}/${device.totalMemory}');
}

final selected = devices.first;
final whisper = await FlutterWhisper.load(
  modelPath: modelPath,
  config: WhisperModelConfig.forDevice(selected),
);

CPU is the safest fallback when a model does not fit in GPU memory. Web device enumeration currently exposes only the WebAssembly CPU runtime.

Windows backend #

AUTO selects Vulkan when a usable Vulkan SDK is detected at build time and falls back to CPU otherwise.

$env:FLUTTER_WHISPER_GPU_BACKEND='CPU'     # CPU, CUDA, VULKAN or AUTO
flutter build windows --release

CUDA requires the CUDA Toolkit. Vulkan requires a Vulkan SDK and shader compiler during the native build. Backend selection changes what is compiled; it cannot enable a GPU in an already-built binary.

Linux backend #

FLUTTER_WHISPER_GPU_BACKEND=CPU flutter build linux --release
FLUTTER_WHISPER_GPU_BACKEND=VULKAN flutter build linux --release

The Vulkan build requires Vulkan development headers, SPIR-V headers/tools and glslc.

Output #

WhisperResult contains detected language, combined text, timestamped segments, optional token metadata, optional VAD regions and native timing data.

final plainText = result.text;
final json = result.toJsonString(pretty: true);
final subtitles = result.toSrt();

final selected = result.format(WhisperOutputFormat.json);

JSON uses a stable schemaVersion: 1 structure. SRT output skips empty cues and normalizes negative or reversed timestamp ranges.

WebAssembly #

Web inference runs outside the Flutter UI thread in a JavaScript Worker. The Worker, Emscripten module and WASM binary are package assets loaded automatically from:

assets/packages/flutter_whisper_ggml/assets/web/

Applications do not copy these files into web/. A model may be an HTTP(S), Flutter asset or browser blob: URL. Browsers cannot read local paths such as C:\models\ggml-small.bin.

The pthread runtime requires these production response headers:

Cross-Origin-Opener-Policy: same-origin
Cross-Origin-Embedder-Policy: require-corp

The minimal example includes a Netlify/Cloudflare-compatible web/_headers file. Verify that the chosen host actually applies the headers and that remote model responses are allowed by its CORS/cross-origin policy.

To rebuild the package Web artifacts, activate Emscripten and run one of:

.\tool\build_web_wasm.ps1 -Configuration Release
bash tool/build_web_wasm.sh Release

CI pins Emscripten 4.0.7 for reproducibility.

Examples #

Minimal package example #

The local example/ is an all-platform smoke application. It lets the user select one GGML .bin model and one WAV file without bundling either file.

cd example
flutter pub get
flutter run -d windows   # linux, macos, android, ios or chrome also work

On Web, selected files become temporary blob: URLs.

Full showcase #

The separate flutter_whisper_ggml_example repository contains the full UI, model dropdown, debugging asset, optional FFmpeg conversion, progress display, live transcript and integration tests. Keeping it separate prevents models and FFmpeg binaries from inflating this package.

Troubleshooting #

Symptom Likely cause Action
Failed to fetch on Web Local filesystem path, CORS or missing isolation headers Select files in the browser, use an allowed URL and verify COOP/COEP
Web Worker failed to load Missing/stale generated Web assets Run the Emscripten build script and rebuild the Flutter app
Only CPU appears GPU backend was not compiled or its SDK/runtime is unavailable Rebuild with CUDA/Vulkan and verify the driver/toolkit
bad magic File is not a GGML Whisper model Select an official ggml-*.bin file
Model reports headers only An upstream for-tests-* fixture was selected Download a real model from the catalog
SHA-256 verification failed Incomplete, changed or intercepted download Retry with forceDownload: true; do not use the partial file
Android download has no network INTERNET permission is absent Add the manifest permission shown in Quick start
WAV rejected Unsupported/corrupt container or samples Convert to mono 16 kHz PCM16 WAV
Repeated/hallucinated segments Weak model, music/noise, clipping or unsuitable decoding settings Improve the WAV, use a stronger multilingual model and tune thresholds/VAD
Out of memory or browser tab crash Model exceeds available RAM/GPU/WASM limits Use a smaller or quantized model and select CPU if GPU memory is limited

Build and validation #

Normal consumers build against the bundled source in whisper/v1.9.2. Maintainers can explicitly test another checkout:

$env:FLUTTER_WHISPER_CPP_DIR='C:\src\whisper.cpp'
flutter build windows

Local quality checks:

flutter pub get
flutter analyze
flutter test

cd example
flutter analyze
flutter test

.github/workflows/ci.yml validates analysis, tests and the pub.dev archive, then builds Android, Linux CPU/Vulkan, Windows CPU, Web/Emscripten, iOS Simulator, unsigned iOS ARM64 and macOS. Real-model integration tests remain in the full example because their fixtures and runtime are too large for the package suite.

Native packaging notes:

  • Android statically links whisper.cpp/GGML into one shared library and supports 16 KiB pages;
  • Linux and Windows package the stable C bridge and selected GGML backends;
  • iOS and macOS compile C++17 sources through CocoaPods with Accelerate;
  • Apple privacy manifests declare no tracking or collected data.

Known limitations #

  • Native file decoding is WAV-only by design.
  • Web currently maps the common language, translation and thread controls; some advanced native decoding controls are not yet forwarded by the Worker.
  • Metal, Android Vulkan and WebGPU are not implemented.
  • The plugin does not provide microphone/live-stream capture.
  • Downloads do not currently expose pause, resume, cancellation or a cache deletion API.
  • Web has no plugin-managed persistent model cache; browser HTTP caching may still reuse a response.
  • Apple platforms are CI-compiled but await physical-device validation.
  • Accuracy, speed and memory depend primarily on model, quantization, audio and hardware.

License #

flutter_whisper_ggml is distributed under the MIT License, copyright (c) 2026 Ruan Dias. Bundled whisper.cpp sources retain their own license notices. Applications must also review the license and usage terms of each model they distribute or download.

2
likes
150
points
91
downloads

Documentation

API reference

Publisher

unverified uploader

Weekly Downloads

Offline speech recognition for Flutter powered by whisper.cpp.

Repository (GitHub)
View/report issues

License

MIT (license)

Dependencies

crypto, ffi, flutter, flutter_web_plugins, path_provider, plugin_platform_interface, web

More

Packages that depend on flutter_whisper_ggml

Packages that implement flutter_whisper_ggml