Skip to content

Version v2.0

You're viewing docs for v2.0. If you are cloning the repository, make sure to check out this release: git checkout v2.0

Quickstart

Install Cactus and run your first on-device AI completion.

Installation

cactus build --apple
cactus build --android

Platform Integration

  1. Add the bridge files from this folder to your React Native app
  2. Add the raw bindings they depend on: bindings/kotlin/ (Android), bindings/swift/ (Apple)
  3. Register the Android package in MainApplication.kt:
    override fun getPackages() = PackageList(this).packages.apply {
        add(com.cactus.reactnative.CactusPackage())
    }
    
cactus build --apple
cactus build --android

Platform Integration

  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
cactus build --android

Platform Integration

  1. Copy android/libcactus_engine.so to app/src/main/jniLibs/arm64-v8a/
  2. Copy Cactus.kt and CactusCallbacks.kt to your Kotlin source tree
cactus build --apple

Platform Integration

XCFramework: drag apple/cactus-ios.xcframework (or apple/cactus-macos.xcframework) into Xcode (Embed & Sign). The framework bundles cactus_engine.h, so import cactus works directly.

Static library: link apple/libcactus_engine-device.a (or apple/libcactus_engine-simulator.a), copy bindings/swift/module.modulemap into your project, and add cactus-engine/ to Header Search Paths so the module map can find cactus_engine.h.

git clone https://github.com/cactus-compute/cactus && cd cactus && source ./setup
cactus build --python
cactus build

Homebrew (macOS):

brew install cactus-compute/cactus/cactus

From Source (macOS):

brew install cmake
git clone https://github.com/cactus-compute/cactus && cd cactus && source ./setup && cactus build --python

From Source (Linux):

sudo apt-get install python3 python3-venv python3-pip cmake build-essential libcurl4-openssl-dev
git clone https://github.com/cactus-compute/cactus && cd cactus && source ./setup && cactus build --python

Include the Cactus header in your project:

#include <cactus_engine.h>

See the Cactus repository for CMake build instructions.


Your First Completion

import Cactus from './index';

const handle = await Cactus.init('/path/to/model', null, false);
const result = await Cactus.complete(handle, messagesJson, null, null, null, false);
await Cactus.destroy(handle);
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);
val handle = CactusJNI.nativeInit("/path/to/model", null, false)
val buf = ByteArray(65536)
CactusJNI.nativeComplete(handle, messagesJson, buf, null, null, null, null)
val response = String(buf, 0, buf.indexOf(0))
CactusJNI.nativeDestroy(handle)
import cactus

let model = cactus_init("/path/to/model", nil, false)
var buf = [CChar](repeating: 0, count: 65536)
cactus_complete(model, messagesJson, &buf, buf.count, nil, nil, nil, nil, nil, 0)
let response = String(cString: buf)
cactus_destroy(model)
from cactus import ensure_model
from cactus import cactus_init, cactus_complete, cactus_destroy
import json

# Downloads the pre-built bundle from HuggingFace if not already present
bundle = ensure_model("LiquidAI/LFM2-VL-450M")

model = cactus_init(str(bundle), None, False)
messages = json.dumps([{"role": "user", "content": "What is 2+2?"}])
result = cactus_complete(model, messages, None, None, None)
print(result["response"])
cactus_destroy(model)
use std::ffi::CString;
use std::os::raw::c_char;

mod cactus;

fn main() {
    unsafe {
        let model_path = CString::new("path/to/weight/folder").unwrap();
        let model = cactus::cactus_init(model_path.as_ptr(), std::ptr::null(), false);

        let messages = CString::new(
            r#"[{"role": "user", "content": "What is the capital of France?"}]"#
        ).unwrap();

        let mut response = vec![0u8; 4096];
        cactus::cactus_complete(
            model, messages.as_ptr(),
            response.as_mut_ptr() as *mut c_char, response.len(),
            std::ptr::null(), std::ptr::null(),
            None, std::ptr::null_mut(),
            std::ptr::null(), 0,
        );

        println!("{}", String::from_utf8_lossy(&response));
        cactus::cactus_destroy(model);
    }
}
cactus run <model|path>
#include <cactus_engine.h>

cactus_model_t model = cactus_init(
    "path/to/weight/folder",
    "path/to/rag/documents",
    false
);

const char* messages = R"([
    {"role": "system", "content": "You are a helpful assistant."},
    {"role": "user", "content": "What is the capital of France?"}
])";

char response[4096];
int result = cactus_complete(
    model, messages, response, sizeof(response),
    nullptr, nullptr, nullptr, nullptr,
    nullptr, 0
);

Next Steps