Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Arendjan/vlm #84

Merged
merged 15 commits into from
Jan 23, 2025
184 changes: 184 additions & 0 deletions lib/interop/generated_bindings.dart
Original file line number Diff line number Diff line change
Expand Up @@ -571,6 +571,128 @@
late final _ttiInferenceClose = _ttiInferenceClosePtr
.asFunction<ffi.Pointer<Status> Function(CLLMInference)>();

ffi.Pointer<StatusOrVLMInference> vlmInferenceOpen(

Check warning on line 574 in lib/interop/generated_bindings.dart

View check run for this annotation

Codecov / codecov/patch

lib/interop/generated_bindings.dart#L574

Added line #L574 was not covered by tests
ffi.Pointer<pkg_ffi.Utf8> model_path,
ffi.Pointer<pkg_ffi.Utf8> device,
) {
return _vlmInferenceOpen(

Check warning on line 578 in lib/interop/generated_bindings.dart

View check run for this annotation

Codecov / codecov/patch

lib/interop/generated_bindings.dart#L578

Added line #L578 was not covered by tests
model_path,
device,
);
}

late final _vlmInferenceOpenPtr = _lookup<
ffi.NativeFunction<
ffi.Pointer<StatusOrVLMInference> Function(ffi.Pointer<pkg_ffi.Utf8>,
ffi.Pointer<pkg_ffi.Utf8>)>>('vlmInferenceOpen');
late final _vlmInferenceOpen = _vlmInferenceOpenPtr.asFunction<
ffi.Pointer<StatusOrVLMInference> Function(
ffi.Pointer<pkg_ffi.Utf8>, ffi.Pointer<pkg_ffi.Utf8>)>();

ffi.Pointer<Status> vlmInferenceSetListener(

Check warning on line 592 in lib/interop/generated_bindings.dart

View check run for this annotation

Codecov / codecov/patch

lib/interop/generated_bindings.dart#L592

Added line #L592 was not covered by tests
CVLMInference instance,
VLMInferenceCallbackFunction callback,
) {
return _vlmInferenceSetListener(

Check warning on line 596 in lib/interop/generated_bindings.dart

View check run for this annotation

Codecov / codecov/patch

lib/interop/generated_bindings.dart#L596

Added line #L596 was not covered by tests
instance,
callback,
);
}

late final _vlmInferenceSetListenerPtr = _lookup<
ffi.NativeFunction<
ffi.Pointer<Status> Function(CVLMInference,
VLMInferenceCallbackFunction)>>('vlmInferenceSetListener');
late final _vlmInferenceSetListener = _vlmInferenceSetListenerPtr.asFunction<
ffi.Pointer<Status> Function(
CVLMInference, VLMInferenceCallbackFunction)>();

ffi.Pointer<StatusOrVLMModelResponse> vlmInferencePrompt(

Check warning on line 610 in lib/interop/generated_bindings.dart

View check run for this annotation

Codecov / codecov/patch

lib/interop/generated_bindings.dart#L610

Added line #L610 was not covered by tests
CVLMInference instance,
ffi.Pointer<pkg_ffi.Utf8> message,
int max_new_tokens,
) {
return _vlmInferencePrompt(

Check warning on line 615 in lib/interop/generated_bindings.dart

View check run for this annotation

Codecov / codecov/patch

lib/interop/generated_bindings.dart#L615

Added line #L615 was not covered by tests
instance,
message,
max_new_tokens,
);
}

late final _vlmInferencePromptPtr = _lookup<
ffi.NativeFunction<
ffi.Pointer<StatusOrVLMModelResponse> Function(CVLMInference,
ffi.Pointer<pkg_ffi.Utf8>, ffi.Int)>>('vlmInferencePrompt');
late final _vlmInferencePrompt = _vlmInferencePromptPtr.asFunction<
ffi.Pointer<StatusOrVLMModelResponse> Function(
CVLMInference, ffi.Pointer<pkg_ffi.Utf8>, int)>();

ffi.Pointer<Status> vlmInferenceSetImagePaths(

Check warning on line 630 in lib/interop/generated_bindings.dart

View check run for this annotation

Codecov / codecov/patch

lib/interop/generated_bindings.dart#L630

Added line #L630 was not covered by tests
CVLMInference instance,
ffi.Pointer<ffi.Pointer<pkg_ffi.Utf8>> paths,
int length,
) {
return _vlmInferenceSetImagePaths(

Check warning on line 635 in lib/interop/generated_bindings.dart

View check run for this annotation

Codecov / codecov/patch

lib/interop/generated_bindings.dart#L635

Added line #L635 was not covered by tests
instance,
paths,
length,
);
}

late final _vlmInferenceSetImagePathsPtr = _lookup<
ffi.NativeFunction<
ffi.Pointer<Status> Function(
CVLMInference,
ffi.Pointer<ffi.Pointer<pkg_ffi.Utf8>>,
ffi.Int)>>('vlmInferenceSetImagePaths');
late final _vlmInferenceSetImagePaths =
_vlmInferenceSetImagePathsPtr.asFunction<
ffi.Pointer<Status> Function(
CVLMInference, ffi.Pointer<ffi.Pointer<pkg_ffi.Utf8>>, int)>();

ffi.Pointer<StatusOrBool> vlmInferenceHasModelIndex(

Check warning on line 653 in lib/interop/generated_bindings.dart

View check run for this annotation

Codecov / codecov/patch

lib/interop/generated_bindings.dart#L653

Added line #L653 was not covered by tests
CVLMInference instance,
) {
return _vlmInferenceHasModelIndex(

Check warning on line 656 in lib/interop/generated_bindings.dart

View check run for this annotation

Codecov / codecov/patch

lib/interop/generated_bindings.dart#L656

Added line #L656 was not covered by tests
instance,
);
}

late final _vlmInferenceHasModelIndexPtr = _lookup<
ffi
.NativeFunction<ffi.Pointer<StatusOrBool> Function(CVLMInference)>>(
'vlmInferenceHasModelIndex');
late final _vlmInferenceHasModelIndex = _vlmInferenceHasModelIndexPtr
.asFunction<ffi.Pointer<StatusOrBool> Function(CVLMInference)>();

ffi.Pointer<Status> vlmInferenceStop(

Check warning on line 668 in lib/interop/generated_bindings.dart

View check run for this annotation

Codecov / codecov/patch

lib/interop/generated_bindings.dart#L668

Added line #L668 was not covered by tests
CVLMInference instance,
) {
return _vlmInferenceStop(

Check warning on line 671 in lib/interop/generated_bindings.dart

View check run for this annotation

Codecov / codecov/patch

lib/interop/generated_bindings.dart#L671

Added line #L671 was not covered by tests
instance,
);
}

late final _vlmInferenceStopPtr =
_lookup<ffi.NativeFunction<ffi.Pointer<Status> Function(CVLMInference)>>(
'vlmInferenceStop');
late final _vlmInferenceStop = _vlmInferenceStopPtr
.asFunction<ffi.Pointer<Status> Function(CVLMInference)>();

ffi.Pointer<Status> vlmInferenceClose(

Check warning on line 682 in lib/interop/generated_bindings.dart

View check run for this annotation

Codecov / codecov/patch

lib/interop/generated_bindings.dart#L682

Added line #L682 was not covered by tests
CVLMInference instance,
) {
return _vlmInferenceClose(

Check warning on line 685 in lib/interop/generated_bindings.dart

View check run for this annotation

Codecov / codecov/patch

lib/interop/generated_bindings.dart#L685

Added line #L685 was not covered by tests
instance,
);
}

late final _vlmInferenceClosePtr =
_lookup<ffi.NativeFunction<ffi.Pointer<Status> Function(CVLMInference)>>(
'vlmInferenceClose');
late final _vlmInferenceClose = _vlmInferenceClosePtr
.asFunction<ffi.Pointer<Status> Function(CVLMInference)>();

ffi.Pointer<StatusOrGraphRunner> graphRunnerOpen(
ffi.Pointer<pkg_ffi.Utf8> graph,
) {
Expand Down Expand Up @@ -861,6 +983,41 @@
external TTIMetrics metrics;
}

final class VLMMetrics extends ffi.Struct {
@ffi.Float()
external double load_time;

@ffi.Float()
external double generate_time;

@ffi.Float()
external double tokenization_time;

@ffi.Float()
external double detokenization_time;

@ffi.Float()
external double ttft;

@ffi.Float()
external double tpot;

@ffi.Float()
external double throughput;

@ffi.Int()
external int number_of_generated_tokens;

@ffi.Int()
external int number_of_input_tokens;
}

final class VLMStringWithMetrics extends ffi.Struct {
external ffi.Pointer<pkg_ffi.Utf8> string;

external VLMMetrics metrics;
}

final class Device extends ffi.Struct {
external ffi.Pointer<pkg_ffi.Utf8> id;

Expand Down Expand Up @@ -966,6 +1123,15 @@
external CLLMInference value;
}

final class StatusOrVLMInference extends ffi.Struct {
@ffi.Int()
external int status;

external ffi.Pointer<pkg_ffi.Utf8> message;

external CLLMInference value;
}

final class StatusOrModelResponse extends ffi.Struct {
@ffi.Int()
external int status;
Expand Down Expand Up @@ -1004,6 +1170,17 @@
external ffi.Pointer<pkg_ffi.Utf8> value;
}

final class StatusOrVLMModelResponse extends ffi.Struct {
@ffi.Int()
external int status;

external ffi.Pointer<pkg_ffi.Utf8> message;

external VLMMetrics metrics;

external ffi.Pointer<pkg_ffi.Utf8> value;
}

final class StatusOrDevices extends ffi.Struct {
@ffi.Int()
external int status;
Expand All @@ -1029,3 +1206,10 @@
typedef DartLLMInferenceCallbackFunctionFunction = void Function(
ffi.Pointer<StatusOrString>);
typedef CTTIInference = ffi.Pointer<ffi.Void>;
typedef CVLMInference = ffi.Pointer<ffi.Void>;
typedef VLMInferenceCallbackFunction
= ffi.Pointer<ffi.NativeFunction<VLMInferenceCallbackFunctionFunction>>;
typedef VLMInferenceCallbackFunctionFunction = ffi.Void Function(
ffi.Pointer<StatusOrString>);
typedef DartVLMInferenceCallbackFunctionFunction = void Function(
ffi.Pointer<StatusOrString>);
7 changes: 7 additions & 0 deletions lib/interop/openvino_bindings.dart
Original file line number Diff line number Diff line change
Expand Up @@ -49,6 +49,13 @@
const TTIModelResponse(this.content, this.metrics);
}

class VLMModelResponse {
final String content;
final VLMMetrics metrics;

const VLMModelResponse(this.content, this.metrics);

Check warning on line 56 in lib/interop/openvino_bindings.dart

View check run for this annotation

Codecov / codecov/patch

lib/interop/openvino_bindings.dart#L56

Added line #L56 was not covered by tests
}


String getLibraryPath() {
if (Platform.isWindows) {
Expand Down
123 changes: 123 additions & 0 deletions lib/interop/vlm_inference.dart
Original file line number Diff line number Diff line change
@@ -0,0 +1,123 @@
// Copyright (c) 2024 Intel Corporation
//
// SPDX-License-Identifier: Apache-2.0

import 'dart:ffi';
import 'dart:isolate';

import 'package:ffi/ffi.dart';
import 'package:inference/interop/openvino_bindings.dart';

final vlmOV = getBindings();

Check warning on line 11 in lib/interop/vlm_inference.dart

View check run for this annotation

Codecov / codecov/patch

lib/interop/vlm_inference.dart#L11

Added line #L11 was not covered by tests

class VLMInference {
NativeCallable<VLMInferenceCallbackFunctionFunction>? nativeListener;
final Pointer<StatusOrVLMInference> instance;
late bool chatEnabled;

VLMInference(this.instance) {
chatEnabled = true;

Check warning on line 19 in lib/interop/vlm_inference.dart

View check run for this annotation

Codecov / codecov/patch

lib/interop/vlm_inference.dart#L18-L19

Added lines #L18 - L19 were not covered by tests
}

static Future<VLMInference> init(String modelPath, String device) async {
final result = await Isolate.run(() {
final modelPathPtr = modelPath.toNativeUtf8();
final devicePtr = device.toNativeUtf8();
final status = vlmOV.vlmInferenceOpen(modelPathPtr, devicePtr);
calloc.free(modelPathPtr);
calloc.free(devicePtr);

Check warning on line 28 in lib/interop/vlm_inference.dart

View check run for this annotation

Codecov / codecov/patch

lib/interop/vlm_inference.dart#L22-L28

Added lines #L22 - L28 were not covered by tests

return status;
});

print("${result.ref.status}, ${result.ref.message}");
if (StatusEnum.fromValue(result.ref.status) != StatusEnum.OkStatus) {
throw "VLMInference open error: ${result.ref.status} ${result.ref.message.toDartString()}";

Check warning on line 35 in lib/interop/vlm_inference.dart

View check run for this annotation

Codecov / codecov/patch

lib/interop/vlm_inference.dart#L33-L35

Added lines #L33 - L35 were not covered by tests
}

return VLMInference(result);

Check warning on line 38 in lib/interop/vlm_inference.dart

View check run for this annotation

Codecov / codecov/patch

lib/interop/vlm_inference.dart#L38

Added line #L38 was not covered by tests
}

Future<void> setListener(void Function(String) callback) async{
int instanceAddress = instance.ref.value.address;
void localCallback(Pointer<StatusOrString> ptr) {
if (StatusEnum.fromValue(ptr.ref.status) != StatusEnum.OkStatus) {

Check warning on line 44 in lib/interop/vlm_inference.dart

View check run for this annotation

Codecov / codecov/patch

lib/interop/vlm_inference.dart#L41-L44

Added lines #L41 - L44 were not covered by tests
// TODO(RHeckerIntel): instead of throw, call an onError callback.
throw "VLM Callback error: ${ptr.ref.status} ${ptr.ref.message.toDartString()}";

Check warning on line 46 in lib/interop/vlm_inference.dart

View check run for this annotation

Codecov / codecov/patch

lib/interop/vlm_inference.dart#L46

Added line #L46 was not covered by tests
}
callback(ptr.ref.value.toDartString());
vlmOV.freeStatusOrString(ptr);

Check warning on line 49 in lib/interop/vlm_inference.dart

View check run for this annotation

Codecov / codecov/patch

lib/interop/vlm_inference.dart#L48-L49

Added lines #L48 - L49 were not covered by tests
}
nativeListener?.close();
nativeListener = NativeCallable<VLMInferenceCallbackFunctionFunction>.listener(localCallback);
final status = vlmOV.vlmInferenceSetListener(Pointer<Void>.fromAddress(instanceAddress), nativeListener!.nativeFunction);
if (StatusEnum.fromValue(status.ref.status) != StatusEnum.OkStatus) {

Check warning on line 54 in lib/interop/vlm_inference.dart

View check run for this annotation

Codecov / codecov/patch

lib/interop/vlm_inference.dart#L51-L54

Added lines #L51 - L54 were not covered by tests
// TODO(RHeckerIntel): instead of throw, call an onError callback.
throw "VLM setListener error: ${status.ref.status} ${status.ref.message.toDartString()}";

Check warning on line 56 in lib/interop/vlm_inference.dart

View check run for this annotation

Codecov / codecov/patch

lib/interop/vlm_inference.dart#L56

Added line #L56 was not covered by tests
}
vlmOV.freeStatus(status);

Check warning on line 58 in lib/interop/vlm_inference.dart

View check run for this annotation

Codecov / codecov/patch

lib/interop/vlm_inference.dart#L58

Added line #L58 was not covered by tests
}


Future<VLMModelResponse> prompt(

Check warning on line 62 in lib/interop/vlm_inference.dart

View check run for this annotation

Codecov / codecov/patch

lib/interop/vlm_inference.dart#L62

Added line #L62 was not covered by tests
String message, int maxNewTokens) async {
int instanceAddress = instance.ref.value.address;
final result = await Isolate.run(() {
final messagePtr = message.toNativeUtf8();
final status = vlmOV.vlmInferencePrompt(
Pointer<Void>.fromAddress(instanceAddress),

Check warning on line 68 in lib/interop/vlm_inference.dart

View check run for this annotation

Codecov / codecov/patch

lib/interop/vlm_inference.dart#L64-L68

Added lines #L64 - L68 were not covered by tests
messagePtr,
maxNewTokens);
calloc.free(messagePtr);

Check warning on line 71 in lib/interop/vlm_inference.dart

View check run for this annotation

Codecov / codecov/patch

lib/interop/vlm_inference.dart#L71

Added line #L71 was not covered by tests
return status;
});

if (StatusEnum.fromValue(result.ref.status) != StatusEnum.OkStatus) {
var msg = result.ref.message;
var status = result.ref.status;
var dStr = msg.toDartString();

Check warning on line 78 in lib/interop/vlm_inference.dart

View check run for this annotation

Codecov / codecov/patch

lib/interop/vlm_inference.dart#L75-L78

Added lines #L75 - L78 were not covered by tests

throw "VLMInference prompt error: $status $dStr";

Check warning on line 80 in lib/interop/vlm_inference.dart

View check run for this annotation

Codecov / codecov/patch

lib/interop/vlm_inference.dart#L80

Added line #L80 was not covered by tests
}

return VLMModelResponse(
result.ref.value.toDartString(), result.ref.metrics);

Check warning on line 84 in lib/interop/vlm_inference.dart

View check run for this annotation

Codecov / codecov/patch

lib/interop/vlm_inference.dart#L83-L84

Added lines #L83 - L84 were not covered by tests
}


void setImagePaths(List<String> paths) {

Check warning on line 88 in lib/interop/vlm_inference.dart

View check run for this annotation

Codecov / codecov/patch

lib/interop/vlm_inference.dart#L88

Added line #L88 was not covered by tests
// Convert Dart strings to C strings
final cStrings = paths.map((str) => str.toNativeUtf8()).toList();

Check warning on line 90 in lib/interop/vlm_inference.dart

View check run for this annotation

Codecov / codecov/patch

lib/interop/vlm_inference.dart#L90

Added line #L90 was not covered by tests

// Create a pointer to the array of C strings
final pointerToCStrings = malloc<Pointer<Utf8>>(cStrings.length);
for (var i = 0; i < cStrings.length; i++) {
pointerToCStrings[i] = cStrings[i];

Check warning on line 95 in lib/interop/vlm_inference.dart

View check run for this annotation

Codecov / codecov/patch

lib/interop/vlm_inference.dart#L93-L95

Added lines #L93 - L95 were not covered by tests
}

final status = vlmOV.vlmInferenceSetImagePaths(instance.ref.value, pointerToCStrings, cStrings.length);

Check warning on line 98 in lib/interop/vlm_inference.dart

View check run for this annotation

Codecov / codecov/patch

lib/interop/vlm_inference.dart#L98

Added line #L98 was not covered by tests

if (StatusEnum.fromValue(status.ref.status) != StatusEnum.OkStatus) {
throw "Close error: ${status.ref.status} ${status.ref.message.toDartString()}";

Check warning on line 101 in lib/interop/vlm_inference.dart

View check run for this annotation

Codecov / codecov/patch

lib/interop/vlm_inference.dart#L100-L101

Added lines #L100 - L101 were not covered by tests
}
vlmOV.freeStatus(status);

Check warning on line 103 in lib/interop/vlm_inference.dart

View check run for this annotation

Codecov / codecov/patch

lib/interop/vlm_inference.dart#L103

Added line #L103 was not covered by tests
}

void forceStop() {
final status = vlmOV.vlmInferenceStop(instance.ref.value);

Check warning on line 107 in lib/interop/vlm_inference.dart

View check run for this annotation

Codecov / codecov/patch

lib/interop/vlm_inference.dart#L106-L107

Added lines #L106 - L107 were not covered by tests

if (StatusEnum.fromValue(status.ref.status) != StatusEnum.OkStatus) {
throw "VLM Force Stop error: ${status.ref.status} ${status.ref.message.toDartString()}";

Check warning on line 110 in lib/interop/vlm_inference.dart

View check run for this annotation

Codecov / codecov/patch

lib/interop/vlm_inference.dart#L109-L110

Added lines #L109 - L110 were not covered by tests
}
}


void close() {
final status = vlmOV.vlmInferenceClose(instance.ref.value);

Check warning on line 116 in lib/interop/vlm_inference.dart

View check run for this annotation

Codecov / codecov/patch

lib/interop/vlm_inference.dart#L115-L116

Added lines #L115 - L116 were not covered by tests

if (StatusEnum.fromValue(status.ref.status) != StatusEnum.OkStatus) {
throw "Close error: ${status.ref.status} ${status.ref.message.toDartString()}";

Check warning on line 119 in lib/interop/vlm_inference.dart

View check run for this annotation

Codecov / codecov/patch

lib/interop/vlm_inference.dart#L118-L119

Added lines #L118 - L119 were not covered by tests
}
vlmOV.freeStatus(status);

Check warning on line 121 in lib/interop/vlm_inference.dart

View check run for this annotation

Codecov / codecov/patch

lib/interop/vlm_inference.dart#L121

Added line #L121 was not covered by tests
}
}
3 changes: 2 additions & 1 deletion lib/pages/download_model/download_model.dart
Original file line number Diff line number Diff line change
Expand Up @@ -100,6 +100,7 @@ class _DownloadModelPageState extends State<DownloadModelPage> {
}

Future<void> onClose() async {
final navigator = Navigator.of(context);
final result = await showDialog<bool>(context: context, builder: (BuildContext context) => ContentDialog(
title: const Text("Download in progress"),
content: const Text("Press 'continue' to keep downloading the model"),
Expand All @@ -117,7 +118,7 @@ class _DownloadModelPageState extends State<DownloadModelPage> {
);

if (result == true && context.mounted) {
GoRouter.of(context).pop();
navigator.pop();
}
}

Expand Down
3 changes: 3 additions & 0 deletions lib/pages/models/inference.dart
Original file line number Diff line number Diff line change
Expand Up @@ -7,6 +7,7 @@ import 'package:inference/pages/computer_vision/computer_vision.dart';
import 'package:inference/pages/text_generation/text_generation.dart';
import 'package:inference/pages/text_to_image/text_to_image_page.dart';
import 'package:inference/pages/transcription/transcription.dart';
import 'package:inference/pages/vlm/vlm_page.dart';
import 'package:inference/project.dart';

class InferencePage extends StatelessWidget {
Expand All @@ -24,6 +25,8 @@ class InferencePage extends StatelessWidget {
return TranscriptionPage(project);
case ProjectType.textToImage:
return TextToImagePage(project);
case ProjectType.vlm:
return VLMPage(project);
}
}

Expand Down
5 changes: 4 additions & 1 deletion lib/pages/text_generation/text_generation.dart
Original file line number Diff line number Diff line change
Expand Up @@ -98,7 +98,10 @@ class _TextGenerationPageState extends State<TextGenerationPage> {
displayMode: PaneDisplayMode.top,
items: [
PaneItem(
icon: const Icon(FluentIcons.game),
icon: SvgPicture.asset("images/playground.svg",
colorFilter: ColorFilter.mode(textColor, BlendMode.srcIn),
width: 15,
),
title: const Text("Playground"),
body: Playground(project: widget.project),
),
Expand Down
Loading
Loading