Skip to content

Flutter Bindings

Dart FFI bindings to cactus_engine.h.

Integration

cactus build --apple
cactus build --android
  1. Copy android/libcactus_engine.so to your app's jniLibs/arm64-v8a/
  2. Add apple/cactus-ios.xcframework to your Xcode project (iOS)
  3. Add apple/cactus-macos.xcframework to your Xcode project (macOS)
  4. Copy cactus.dart into your Dart source tree
  5. Add ffi to pubspec.yaml

Usage

import 'dart:ffi';
import 'cactus.dart';
import 'package:ffi/ffi.dart';

final modelPath = '/path/to/model'.toNativeUtf8();
final model = cactusInit(modelPath, nullptr, false);
calloc.free(modelPath);

const messagesJson = '[{"role":"user","content":"Hello"}]';
final msgs = messagesJson.toNativeUtf8();
final buf = calloc<Int8>(65536);
cactusComplete(model, msgs, buf.cast(), 65536, nullptr, nullptr, nullptr, nullptr, nullptr, 0);
final response = buf.cast<Utf8>().toDartString();
calloc.free(msgs);
calloc.free(buf);
cactusDestroy(model);

Streaming transcription

Push 16 kHz mono PCM16 as it arrives; each call returns {"success":true,"confirmed":...,"pending":...} (confirmed is final, pending is the volatile tail).

final opts = '{"language":"en"}'.toNativeUtf8();
final stream = cactusStreamTranscribeStart(model, opts);
final out = calloc<Int8>(65536);
for (final chunk in pcmChunks) { // each: 16 kHz mono PCM16 bytes
  final p = calloc<Uint8>(chunk.length)..asTypedList(chunk.length).setAll(0, chunk);
  cactusStreamTranscribeProcess(stream, p, chunk.length, out.cast(), 65536);
  calloc.free(p);
  // parse {"confirmed":...,"pending":...} from out.cast<Utf8>().toDartString()
}
cactusStreamTranscribeStop(stream, out.cast(), 65536);
calloc.free(opts);
calloc.free(out);