dart_vector_embedding 0.1.1 copy "dart_vector_embedding: ^0.1.1" to clipboard
dart_vector_embedding: ^0.1.1 copied to clipboard

Cross-platform Dart Native GGUF embeddings via llama.cpp with shared per-model concurrency and native async callbacks.

dart_vector_embedding #

Cross-platform Dart Native GGUF embeddings through vendored llama.cpp with one shared native runtime per model path, native queued execution, and async multi-isolate access.


Features #

  • Native llama.cpp embeddings through dart:ffi
  • Async Embedder.open(...), embed(...), embedBatch(...), and close()
  • One shared native llama_model + llama_context per canonical model path inside a Dart process
  • One native worker thread per shared model path with queued request execution
  • Symmetric multi-isolate access without each isolate loading a duplicate model
  • GPU offload when the host/backend supports it
  • Works with dart run, dart test, and dart build cli
  • Cross-platform native assets: macOS, Linux, Windows

Why This Package #

Most Dart-side local embedding wrappers either assume a single isolate, require callers to manage a native sidecar manually, or expose a much broader llama.cpp surface than an embedding workload needs.

dart_vector_embedding exists for the case where multiple isolates in the same Dart process need to generate embeddings against the same local GGUF model efficiently.

Native efficiency. Tokenization and embedding execution run in C++ through dart:ffi, not in the Dart VM. This means:

  • No duplicate model load for every isolate in the same process
  • No Dart-side queue or coordinator isolate required
  • Native request serialization around one shared llama.cpp runtime
  • Async completion back into Dart without Isolate.run

Core concurrency model:

  • opening the same model path from multiple isolates attaches them to one shared native runtime
  • requests for that model path are queued in native code
  • one dedicated native worker thread executes requests one at a time
  • up to 64 requests may wait per model; excess requests fail with VeQueueFullException
  • callers await Futures and remain free to do other work

This lets you build isolate-heavy CLI or server workloads without loading the same GGUF model separately in every isolate.


Native Build Requirements #

The Dart build hook runs CMake automatically, but the host must provide:

  • CMake 3.19 or newer
  • A C/C++17 toolchain: Xcode Command Line Tools on macOS, GCC/Clang on Linux, or Visual Studio Build Tools on Windows

CUDA and Vulkan SDKs are optional. Without them, the package builds with Metal on macOS or CPU support on other platforms.


Getting Started #

1. Add dependency #

dependencies:
  dart_vector_embedding: ^0.1.1

2. Import the package #

import 'package:dart_vector_embedding/dart_vector_embedding.dart';

3. Open the embedder and generate embeddings #

final embedder = await Embedder.open(
  modelPath: '/absolute/path/to/model.gguf',
  outDim: 256,
);

try {
  final query = await embedder.embed('Which planet is known as the Red Planet?');

  final docs = await embedder.embedBatch([
    'Mars is the Red Planet.',
    'Saturn has prominent rings.',
  ]);

  print('query dim: ${query.length}');
  print('docs: ${docs.length}');
} finally {
  await embedder.close();
}

See example/example.dart.


How Should I Run It #

dart run #

Use this for normal development.

dart run bin/your_app.dart

The native library is built and loaded automatically through Dart hooks/code assets. No manual cmake step or libraryPath argument is required.

This mode preserves the shared native runtime behavior for multiple isolates inside the same Dart process.

Build a distributable CLI #

Packages with Dart build hooks, including dart_vector_embedding, must be compiled with dart build cli. It produces a self-contained application bundle with the executable in bin/ and its native libraries in lib/.

dart build cli --target bin/your_app.dart --output dist

For example, on macOS the output is:

dist/bundle/bin/your_app
dist/bundle/lib/libdart_vector_embedding.dylib

Ship the entire dist/bundle/ directory. On Linux the library is named libdart_vector_embedding.so; on Windows it is dart_vector_embedding.dll.

At runtime, dart_vector_embedding resolves native code in this order:

  1. Dart native-asset mapping, if available
  2. DART_VECTOR_EMBEDDING_LIBRARY_PATH, if set
  3. the executable directory

Example override:

DART_VECTOR_EMBEDDING_LIBRARY_PATH=/opt/dve/libdart_vector_embedding.so ./your_app

Only use an override path controlled by your application deployment.


Models #

  • This package does not bundle model files.
  • Use any compatible GGUF embedding model and pass its path into Embedder.open(...).
  • Development-only local model setup notes may exist in the repository, but they are not part of the published package.

Concurrency Model #

  • Same process, same model path: one shared native model/context slot
  • Same process, multiple isolates: all isolates can attach to that same slot
  • Requests for a shared model path: queued in native code and executed sequentially on one native worker thread
  • Queue limit: 64 waiting requests per shared model path; excess requests fail immediately with VeQueueFullException
  • Request limits: 1 MiB of UTF-8 text per item, 4 MiB total batch text, and 256 items per batch
  • Model paths and embedding text must not contain NUL characters
  • Completion back to Dart: async callback -> Future

Shared-runtime attachment rules:

  • outDim, nCtx, pooling, and normalize must match the slot's effective configuration
  • outDim is compared after native clamping, so 0 and values above the model embedding dimension both resolve to full model dimension
  • nThreads uses a first-opener-wins policy; later attaches reuse the existing runtime thread count

This is one of the package's core design goals: isolate-friendly shared native embeddings, not just local single-isolate inference.


GPU Behavior #

GPU offload is enabled when a supported build toolchain is detected.

  • macOS: Metal
  • Linux/Windows with a CUDA compiler: CUDA
  • Linux/Windows with a Vulkan SDK, glslc, and SPIR-V headers: Vulkan

CUDA and Vulkan detection happens during the native hook build. Missing GPU toolchains are not errors; the package falls back to CPU automatically.


Supported Platforms #

The hook and native source are configured for:

  • macOS
  • Linux
  • Windows

Web is unsupported because this package depends on native FFI.


API Overview #

Embedder #

Method / Property Description
Embedder.open(...) Open or attach to a shared native embedding runtime
embed(text) Embed one string
embedBatch(texts) Embed multiple strings
close() Release this Dart handle
outDim Effective output dimension of this slot

PoolingType #

  • PoolingType.mean
  • PoolingType.cls
  • PoolingType.last

Third-party Source #

  • Native sources are vendored under third_party/llama.cpp
  • No consumer git submodule update step is required
  • Upstream pin and update notes live in third_party/llama.cpp/UPSTREAM.md

Running Tests #

The tests use the 300M Q4_0 EmbeddingGemma model and do not download it automatically. From the package root:

mkdir -p models
curl -L \
  https://huggingface.co/ggml-org/embeddinggemma-300M-qat-q4_0-GGUF/resolve/main/embeddinggemma-300M-qat-Q4_0.gguf \
  -o models/embeddinggemma-300M-qat-Q4_0.gguf

The model is approximately 278 MB. It comes from the ggml-org EmbeddingGemma GGUF repository.

Then run:

dart analyze
dart test
bash test/run_native_regression.sh

To use an existing model at another location:

DART_VECTOR_EMBEDDING_TEST_MODEL=/path/to/model.gguf dart test

bash test/run_all.sh remains an equivalent convenience wrapper around dart test.

Release Check #

Maintainers can run all publish checks with:

bash tools/check_release.sh

It runs formatting, analysis, model-backed Dart and native regression tests when a local test model is available, and dart pub publish --dry-run. It never downloads a model automatically.

Benchmark #

The benchmark opens the same model with outDim: 256, performs five warmup embeddings, then reports the average sequential embedding duration. Model load time is excluded.

dart run benchmark/embed_benchmark.dart

Pass a model path and iteration count explicitly if needed:

dart run benchmark/embed_benchmark.dart /path/to/model.gguf 100
0
likes
160
points
29
downloads

Documentation

API reference

Publisher

unverified uploader

Weekly Downloads

Cross-platform Dart Native GGUF embeddings via llama.cpp with shared per-model concurrency and native async callbacks.

Repository (GitHub)
View/report issues

Topics

#ffi #embeddings #gguf #llama-cpp

License

MIT (license)

Dependencies

code_assets, ffi, hooks, native_toolchain_c

More

Packages that depend on dart_vector_embedding