convertOrtValue method
Converts an OrtValue to a different data type
valueId
is the ID of the OrtValue to convert
targetType
is the target data type (e.g., 'float32', 'float16')
Implementation
@override
Future<Map<String, dynamic>> convertOrtValue(String valueId, String targetType) async {
try {
// Check if the tensor exists
if (!_ortValues.containsKey(valueId)) {
throw PlatformException(code: "INVALID_VALUE", message: "OrtValue with ID $valueId not found", details: null);
}
final tensor = _ortValues[valueId]!;
// Get tensor type and shape
final sourceType = getProperty(tensor, 'type').toString();
final jsShape = getProperty(tensor, 'dims');
final shapeLength = getProperty(jsShape, 'length') as int;
final shape = <int>[];
for (var i = 0; i < shapeLength; i++) {
shape.add(callMethod(jsShape, 'at', [i]) as int);
}
// Get the Tensor constructor from onnxruntime-web
final tensorClass = getProperty(_ort, 'Tensor');
// Get the data from the tensor
final jsData = getProperty(tensor, 'data');
final dataLength = getProperty(jsData, 'length') as int;
// Create a new tensor based on the conversion type
JSObject newTensor;
// Handle different conversion scenarios
switch ('$sourceType-$targetType') {
// Float32 to Int32
case 'float32-int32':
final intArray = [];
for (var i = 0; i < dataLength; i++) {
final value = callMethod(jsData, 'at', [i]) as num;
intArray.add(value.toInt());
}
final jsIntArray = _convertToTypedArray(intArray, 'Int32Array');
newTensor = js_util.callConstructor(tensorClass, ['int32', jsIntArray, jsArrayFrom(shape)]);
break;
// Float32 to Int64 (BigInt64Array)
case 'float32-int64':
// For int64 conversions in web, we need to skip the test
// since BigInt64Array is not properly supported in all browsers
// Throw a more user-friendly error
throw PlatformException(
code: "CONVERSION_ERROR",
message: "Int64 conversions are not fully supported in the web implementation yet",
details: null,
);
// Int32 to Float32
case 'int32-float32':
final floatArray = [];
for (var i = 0; i < dataLength; i++) {
final value = callMethod(jsData, 'at', [i]) as num;
floatArray.add(value.toDouble());
}
final jsFloatArray = _convertToTypedArray(floatArray, 'Float32Array');
newTensor = js_util.callConstructor(tensorClass, ['float32', jsFloatArray, jsArrayFrom(shape)]);
break;
// Int64 to Float32
case 'int64-float32':
final floatArray = [];
for (var i = 0; i < dataLength; i++) {
final jsValue = callMethod(jsData, 'at', [i]);
final value = js_util.dartify(jsValue);
// Convert value to double, handle null or non-numeric cases
double doubleValue = 0.0;
if (value != null) {
if (value is num) {
doubleValue = value.toDouble();
} else if (value is String) {
doubleValue = double.tryParse(value) ?? 0.0;
}
}
floatArray.add(doubleValue);
}
final jsFloatArray = _convertToTypedArray(floatArray, 'Float32Array');
newTensor = js_util.callConstructor(tensorClass, ['float32', jsFloatArray, jsArrayFrom(shape)]);
break;
// Int32 to Int64
case 'int32-int64':
// For int64 conversions in web, we need to skip the test
// since BigInt64Array is not properly supported in all browsers
// Throw a more user-friendly error
throw PlatformException(
code: "CONVERSION_ERROR",
message: "Int64 conversions are not fully supported in the web implementation yet",
details: null,
);
// Int64 to Int32 (with potential loss of precision)
case 'int64-int32':
final intArray = [];
for (var i = 0; i < dataLength; i++) {
final jsValue = callMethod(jsData, 'at', [i]);
final value = js_util.dartify(jsValue);
// Convert value to int, handle null or non-numeric cases
int intValue = 0;
if (value != null) {
if (value is num) {
intValue = value.toInt();
} else if (value is String) {
intValue = int.tryParse(value) ?? 0;
}
}
intArray.add(intValue);
}
final jsIntArray = _convertToTypedArray(intArray, 'Int32Array');
newTensor = js_util.callConstructor(tensorClass, ['int32', jsIntArray, jsArrayFrom(shape)]);
break;
// Uint8 to Float32
case 'uint8-float32':
final floatArray = [];
for (var i = 0; i < dataLength; i++) {
final value = callMethod(jsData, 'at', [i]) as num;
floatArray.add(value.toDouble());
}
final jsFloatArray = _convertToTypedArray(floatArray, 'Float32Array');
newTensor = js_util.callConstructor(tensorClass, ['float32', jsFloatArray, jsArrayFrom(shape)]);
break;
// Boolean to Int8/Uint8
case 'bool-int8':
case 'bool-uint8':
// Boolean values are already stored as 0/1 in a Uint8Array
// Just create a new Uint8Array with the same values
final byteArray = [];
for (var i = 0; i < dataLength; i++) {
final value = callMethod(jsData, 'at', [i]) as num;
byteArray.add(value != 0 ? 1 : 0);
}
final jsByteArray = _convertToTypedArray(byteArray, 'Uint8Array');
newTensor = js_util.callConstructor(tensorClass, ['uint8', jsByteArray, jsArrayFrom(shape)]);
break;
// Int8/Uint8 to Boolean
case 'int8-bool':
case 'uint8-bool':
// Convert to boolean representation (non-zero values become true)
final boolArray = [];
for (var i = 0; i < dataLength; i++) {
final value = callMethod(jsData, 'at', [i]) as num;
boolArray.add(value != 0 ? 1 : 0);
}
final jsBoolArray = _convertToTypedArray(boolArray, 'Uint8Array');
newTensor = js_util.callConstructor(tensorClass, ['bool', jsBoolArray, jsArrayFrom(shape)]);
break;
// Same type conversion (no-op)
case 'float32-float32':
case 'int32-int32':
case 'int64-int64':
case 'uint8-uint8':
case 'int8-int8':
case 'bool-bool':
case 'string-string':
// Clone the original tensor with the same data
final newData = getProperty(tensor, 'data');
newTensor = js_util.callConstructor(tensorClass, [sourceType, newData, jsArrayFrom(shape)]);
break;
default:
throw PlatformException(
code: "CONVERSION_ERROR",
message: "Conversion from $sourceType to $targetType is not supported",
details: null,
);
}
// Generate a unique ID for this tensor
final newValueId = '${DateTime.now().millisecondsSinceEpoch}_${math.Random().nextInt(10000)}';
// Store the tensor
_ortValues[newValueId] = newTensor;
// Return the tensor information
return {'valueId': newValueId, 'dataType': targetType, 'shape': shape};
} catch (e) {
if (e is PlatformException) {
rethrow;
}
throw PlatformException(code: "CONVERSION_ERROR", message: "Failed to convert OrtValue: $e", details: null);
}
}