fonnx 0.2.0
fonnx: ^0.2.0 copied to clipboard
ONNX model inference for Dart and Flutter on every platform: ONNX Runtime through FFI on native, Web Workers on the web. Embeddings, Whisper speech to text, Kokoro text to speech, and more.
[FONNX image header, bird like Flutter mascot DJing. Text reads: FONNX. Any model on any edge. Run ONNX model & runtime, with platform-specific acceleration, inside Flutter, a modern, beautiful, cross-platform development framework.]
Changelog #
2026 Sep 29 #
- Moved the Potion 32M tokenizer into an opt-in library so 8M-only apps no
longer load the 32M vocabulary in debug builds. Replace
MinishLab.potion32mTokenizerwithpotion32mTokenizerand importpackage:fonnx/tokenizers/potion_32m_tokenizer.dart.MinishLab.potion8mTokenizeris unchanged.
2026 Aug 24 #
- Pronunciation transcription can preserve exact decoder token IDs, identify their vocabulary, decode them without re-tokenization, and feed compatible token sequences directly back into keyword matching.
2026 Aug 9 #
- Added runtime-configurable English keyword spotting on Android, iOS, Linux, macOS, Windows, and Web.
- All native targets use the same Dart FFI worker through Native Assets; no Kotlin, Swift, CocoaPods, Maven, or model-specific native runner is needed.
- Added runtime phrase replacement, pronunciation aliases, teach-by-voice transcription, streaming fixtures, and Android/iOS integration tests.
- Added the ORT 1.27.0 Apple SME Zipformer workaround. It is scoped to the encoder session and can be removed after upgrading the Native Asset to fixed ORT 1.27.1 or newer.
2026 Jul 20 #
- Upgraded ONNX Runtime from 1.16.1 to 1.27.0 on every native platform.
- Replaced vendored binaries, CocoaPods, Maven runtime dependencies, and Kotlin/Swift platform channels with SHA-256-verified native code assets and one Dart FFI inference implementation.
- Added Linux aarch64 support for Raspberry Pi/flutter-pi.
- Removed ONNX Runtime Extensions. Every model runs on core ORT; tokenizers and token decoding are in Dart.
- Native support is Android armv7/arm64/x64, iOS arm64 device/simulator, Linux x64/aarch64, macOS arm64, and Windows x64/arm64. Intel macOS is dropped.
2026 Jul 19 #
- Upgraded voice activity detection to the official Silero VAD v6.2.1 model.
- Added the v6 streaming state/context contract on native, mobile, and web.
2024 Apr 22 #
- CI builds for all platforms are now running on Codemagic..
2024 Feb 26 #
- Google's Magika for file identification supported on all platforms.
- Example app including full voice assistant flow, with Whisper, Silero voice activity detection. Available at telosnex.github.io/fonnx/
2024 Feb 19 #
- Whisper supported on all platforms, including web.
2024 Feb 13 #
- Whisper now supported on all platforms besides web.
- Whisper models support timestamps. (not exposed via API, yet)
- Silero VAD added to all platforms besides web.
- Silero VAD enables detecting when the user is done speaking with a much higher success rate than relying on volume levels.
- Example contains
SttService, an example of how to integrate the VAD and Whisper together with an easy to use interface. (Stream
FONNX #
Any model on any edge #
Run ML models natively on any platform. ONNX models can be run on iOS, Android, Web, Linux, Windows, and macOS.
What is FONNX? #
FONNX is a Flutter library for running ONNX models. Flutter, and FONNX, run natively on iOS, Android, Web, Linux, Windows, and macOS. FONNX leverages ONNX to provide native acceleration capabilities, from CoreML on iOS, to Android Neural Networks API on Android, to WASM SIMD on Web. Most models can be easily converted to ONNX format, including models from Pytorch, Tensorflow, and more.
Getting ONNX Models #
Hugging Face #
🤗 Hugging Face has a large collection of models, including many that are ONNX format. 90% of the models are Pytorch, which can be converted to ONNX.
Here is a search for ONNX models.
Export ONNX from Pytorch, Tensorflow, & more #
A command-line tool called optimum-cli from HuggingFace converts Pytorch and Tensorflow models. This covers the vast majority of models. optimum-cli can also quantize models, significantly reduce model size, usually with negligible impact on accuracy.
See official documentation or the
quick start snippet on GitHub.
Another tool that automates conversion to ONNX is HFOnnx. It was used to export the text embeddings models in this repo. Its advantages included a significantly smaller model size, and incorporating post-processing (pooling) into the model itself.
- Brief intro to how ONNX model format & runtime work huggingface.com
- Netron allows you to view ONNX models, inspect their runtime graph, and export them to other formats
FUTO keyboard models #
FutoSwipe provides offline English QWERTY swipe decoding, next-word
prediction, and ContextLM word scoring from the FUTO Swipe models:
final swipe = await FutoSwipe.load(
bundle: FutoSwipeBundle.fromDirectory(modelDirectory),
lexicon: const [FutoSwipeWord('hello', frequency: 200)],
);
final candidates = await swipe.decode(points, previousWords: const ['say']);
lib/models/futo_swipe/README.md documents the API contract, pipeline, and
validation. The Web requires futo_swipe_init.js and futo_swipe_worker.js.
The converted bundle is in example/assets/models/futoSwipe/. It has the swipe
encoder, the English QWERTY decoder, ContextLM, and get_embeddings.onnx. All
graphs use core ONNX opset 17 and need no custom operators. manifest.json
records the tensor contracts, source revisions, and hashes. The vocabulary,
scoring configuration, metadata, license, and NOTICE.txt are distributed with
the models. The artifact gate verifies every file.
The bundle is derived from FUTO Swipe and is subject to the FUTO Model Weights
License 1.0 in LICENSE-FUTO.txt. Products must display visible FUTO Swipe
attribution. Neither the conversion nor the runtime uses the GPL swipe library.
To reproduce the bundle, use FlatBuffers flatc 25.2.10 and an empty output
directory:
dart run tool/futo/convert.dart /tmp/futo-swipe-onnx /path/to/flatc
The Dart converter translates the pinned .pte graphs and copies their FP32
weights. It needs no Python, training checkpoint, or ExecuTorch runtime.
Inference is not bit-exact with ExecuTorch, especially near sigmoid saturation.
test/data/futo_swipe/validation.json records the one-off numerical
comparison. The network-enabled replay in tool/futo/replay.dart sends 1,000
raw public swipes through FutoSwipe.decode. It checks the results against
frozen ExecuTorch top-three candidates. All FUTO-specific tools are in
tool/futo/.
Text Embeddings #
These models generate embeddings for text.
An embedding is a vector of floating point numbers that represents the meaning of the text.
Embeddings are the foundation of a vector database, as well as retrieval augmented generation - deciding which text snippets to provide in the limited context window of an LLM like GPT.
Running locally using FONNX provides significant privacy benefits, as well as latency benefits. For example, rather than having to store the embedding and text of each chunk of a document on a server, they can be stored on-device. Both MiniLM L6 V2 and MSMARCO MiniLM L6 V3 are both the product of the Sentence Transformers project. Their website has excellent documentation explaining, for instance, semantic search
MiniLM L6 V2
Trained on a billion sentence pairs from diverse sources, from Reddit to WikiAnswers to StackExchange.
MiniLM L6 V2 is well-suited for numerous tasks, from text classification to semantic search.
It is optimized for symmetric search, where text is roughly of the same length and meaning.
Input text is divided into approximately 200 words, and an embedding is generated for each.
🤗 Hugging Face
MSMARCO MiniLM L6 V3
Trained on pairs of Bing search queries to web pages that contained answers for the query.
It is optimized for asymmetric semantic search, matching a search query to an answer.
Additionally, it has 2x the input size of MiniLM L6 V2: it can accept up to 400 words as input for one embedding.
🤗 Hugging Face
Benchmarks
iPhone 14: 67 ms
Pixel Fold: 33 ms
macOS: 13 ms
WASM SIMD: 41 ms
Avg. ms for 1 Mini LM L6 V2 embedding / 200 words.
- Run on Thurs Oct 12th 2023.
- macOS and WASM-SIMD runs on MacBook Pro M2 Max.
- Average of 100 embeddings, after a warmup of 10.
- Input is mix of lorem ipsum text from 8 languages.
Integrating FONNX #
Open-vocabulary keyword spotting #
The 5 MB GigaSpeech Zipformer bundle detects English phrases selected at runtime. It accepts streaming mono 16 kHz PCM, supports atomic phrase changes, and can learn pronunciation aliases from a recording. Native targets share one Dart FFI implementation; Web uses an ONNX Runtime worker with the same Dart frontend and decoder.
final spotter = await KeywordSpotter.load(
bundle: KeywordSpotterBundle.gigaSpeech3m(modelDirectory),
keywords: const [
KeywordPhrase('telosnex', spokenForms: ['tell us next']),
],
);
spotter.detections.listen((event) => print(event.phrase));
await spotter.acceptPcm16(microphoneBytes);
await spotter.close();
See the keyword spotter documentation and the example's realtime phrase editor.
Native platforms via Dart FFI and code assets #
Android, iOS, Linux, macOS, and Windows use the same Dart FFI implementation.
hook/build.dart uses package:kiln and
native_artifacts/prebuilt.json. If the package sources match the release,
it downloads and checks two bundled code assets: ONNX Runtime and the session
finalizer. No C compiler is needed for a released package. Microsoft supplies
the pinned ORT archives except on iOS, where FONNX supplies its existing
dynamic ORT base. FONNX release CI builds the finalizer through the same hook
that runs local source builds.
The native_build user define selects auto (default), download, or
source. In auto mode, a source change makes the hook compile the finalizer.
ORT remains a pinned upstream input in both modes. Source builds need CMake
and a target compiler. Apple targets build on macOS,
Linux on Linux, Windows on Windows, and Android with the pinned NDK.
hooks:
user_defines:
fonnx:
native_build: source
There are no FONNX CocoaPods/Gradle native dependencies and no platform channels.
Microsoft's published iOS artifact is static and cannot be loaded as a Dart code asset. FONNX release CI runs Microsoft's official Apple framework script in its supported dynamic mode and publishes arm64 device/simulator artifacts for the hook. iOS 15.1 or newer is required. macOS 14 or newer and Apple Silicon are required; Intel support was intentionally dropped. Linux releases build on Ubuntu 22.04 and run with glibc 2.35 and its libstdc++. Windows requires the Microsoft Visual C++ 2015–2022 runtime. The package profile records these requirements.
Flutter reports iOS 13 and macOS 13 to hooks regardless of the app's target. FONNX uses its declared iOS 15.1/macOS 14 floors for prebuilt selection. The manifest keeps the real minima. Compiling from source cannot lower the minimum of the pinned ORT input.
Required iOS project setup #
Set both the Runner deployment target and platform :ios in the Podfile to
15.1 or newer. Flutter 3.44.2's iOS native-assets pipeline generates framework
Info.plist files with Flutter's iOS 13 baseline. It does not currently derive
that value from a consuming Runner project's higher deployment target. The
related upstream history is flutter/flutter#148044,
and Flutter's source TODO points to the still-open
flutter/flutter#145104.
ORT 1.27's Apple Mach-O binaries require iOS 15.1. App Store Connect rejects a
framework that advertises a lower minimum than its binary with ITMS-90208.
Until Flutter propagates the app target into native-asset packaging, add a Run
Script phase immediately after Flutter's Thin Binary phase. The phase
must set MinimumOSVersion on onnxruntime.framework to
IPHONEOS_DEPLOYMENT_TARGET, verify that this minimum is not lower than the
embedded Mach-O minimum, and re-sign the modified framework. The complete fail-closed
implementation is in
example/ios/fix_fonnx_framework_minimum_os.sh,
and the example Xcode project shows the required phase ordering.
Runtime model downloads #
The model files are on Hugging Face in
telosnex/fonnx, not in Git. The
generated prebuiltRuntimeFiles catalog pins the 23 model files: each URL
names a Hugging Face commit, and the catalog has each file's size and SHA-256.
Apps download a model after install:
import 'package:fonnx/runtime_models.dart';
final model = await ensureFonnxRuntimeModel(
'pyannote/pyannote_seg3.onnx',
modelDirectory,
);
The helper checks an existing file before reuse. It checks each download before
it puts the file at its final path. The FUTO model names are distinct on
Hugging Face and map back to their source paths through
runtimeModelNamesByPath. Tokenizers, FUTO metadata, and license notices are
separate from the ONNX model files.
The tests and the example app read the models in example/assets/models.
To download them there, run:
dart run tool/fetch_hf_models.dart # all models, 1.5 GB
dart run tool/fetch_hf_models.dart whisper # one directory
To add or change a model, put the file in example/assets/models, add its
entry without a commit to the models section of
native_artifacts/manifest.json and to runtimeModelNamesByPath, then run
dart run tool/publish_models.dart. It uploads the new files in one Hugging
Face commit with hf upload, records the commit, and writes the catalog. A
published file never changes. doc/ADR_001_MODELS_ON_HUGGING_FACE.md has the
design.
To publish the native libraries and the web files, push to kiln-release,
then merge the kiln-manifest/<tag> branch that
.github/workflows/kiln_release.yml pushes. Push to kiln-release-dry for
a build-only run. The shared workflow of Telosnex/telosnex_ci_tools runs
the fonnx steps in tool/kiln/. tool/kiln/release.dart preserves the
upstream ORT URLs when it writes the manifest. The two iOS ORT files are
copied unchanged into the new immutable release.
Web #
FONNX ships a local ONNX Runtime Web 1.31.1 reference runtime in lib/web
(mirrored into example/web in this repository).
Every model Worker imports ./ort.min.mjs; no executable CDN dependency is
used. The same version backs native and Web inference, and the package manifest
locks the JS module, Emscripten side module, Wasm, workers, deployed copies, and
supported model fixtures. Copy the required init/Worker files plus the three
ort* runtime files from lib/web into the consuming app's web/ directory.
Run the complete package gate with:
tool/test_all.sh
It downloads the models, verifies source/artifact/model hashes, executes a
real local Web identity and Magika Worker model, runs the package-owned
finalizer through 8,192 ASan/UBSan ownership states, checks exact native
ORT artifacts plus model goldens/RSS tests serially, and
runs the deterministic frontend corpus through VM, Chrome JavaScript, and
Chrome Wasm. Set FONNX_FULL_RUNTIME_MATRIX=1 to include iOS Simulator,
Android, Linux arm64/x64, and Windows/Wine artifact execution.
Sending these headers with the request for the ONNX JS package gives a 10x speedup:
Cross-Origin-Embedder-Policy: require-corp
Cross-Origin-Opener-Policy: same-origin
See this GitHub issue for details. TL;DR: It allows use of multiple threads by ONNX's WASM implementation by using a SharedArrayBuffer.
Developing with Web #
Serve .wasm as application/wasm. For multithreaded inference, serve both
cross-origin isolation headers shown above; ORT falls back to one thread when
SharedArrayBuffer is unavailable. flutter run -d chrome is sufficient for
single-threaded development and requires no CDN download or browser extension.
License #
FONNX is licensed under the MIT License. See LICENSE, which also has the licenses of the code it bundles (ONNX Runtime and ONNX Runtime Extensions).