Melange
Platform IntegrationFlutter

Basic Inference

Run your first AI model inference in Flutter with ZETIC Melange.

This guide shows how to run inference from Dart after completing the Flutter setup.

Prerequisites

  • zetic_mlange added to your Flutter project
  • Platform setup completed for Android or iOS
  • A compiled model on the Melange Dashboard
  • Your Personal Key and model name in account_name/project_name format

Running Inference

import 'dart:typed_data';

import 'package:zetic_mlange/zetic_mlange.dart';

// (1) Load model
// This handles model download, cache reuse, and native runtime initialization.
final model = await ZeticMLangeModel.create(
  personalKey: personalKey,
  name: 'account_name/project_name',
  onProgress: (progress) {
    print('Loading ${(progress * 100).round()}%');
  },
);

// (2) Prepare model inputs
// Ensure shape and dtype match your model's input specification.
final input = Tensor.float32View(
  Float32List.fromList([/* preprocessed values */]),
  shape: const [1, 3, 224, 224],
);

// (3) Run inference
final outputs = model.run([input]);

// (4) Read output data
final scores = outputs.first.asFloat32List();

model.close();

Understanding the Flow

  1. Model Download: On first use, the native SDK downloads the hardware-optimized model artifact for the current platform.
  2. Native Runtime Creation: The Flutter SDK calls the Android or iOS SDK through FFI and receives a native model handle.
  3. Tensor Copy and Execution: Dart Tensor bytes are copied into native input buffers, the model runs on the selected backend, and output tensors are returned to Dart as typed views.

Input tensor shapes and data types must match the model's input specification. A mismatch throws MlangeException or a native SDK error.

Tensor Inputs

Use the typed constructors that match your preprocessing output:

final floatInput = Tensor.float32View(
  floatValues,
  shape: const [1, 3, 224, 224],
);

final intInput = Tensor.int64View(
  tokenIds,
  shape: const [1, 128],
);

Use View constructors when your typed list is already in the correct layout and can be shared without an extra Dart-side copy. Use List constructors when you want defensive copy semantics.

Model Lifetime

Keep the model instance alive while you reuse it, then release the native handle when the screen or service is done:

if (!model.isClosed) {
  model.close();
}

Flutter does not expose Android's allocation-free getInputBuffers() path. run(inputs) copies each Dart tensor into the native model input buffer before execution.

Sample Applications

Please refer to the ZETIC Melange Apps repository for complete Flutter sample applications.


Next Steps

On this page