diff --git a/src/bindings/js/node/include/compiled_model.hpp b/src/bindings/js/node/include/compiled_model.hpp index 4e3834a3a527bd..56c483064be9ec 100644 --- a/src/bindings/js/node/include/compiled_model.hpp +++ b/src/bindings/js/node/include/compiled_model.hpp @@ -71,6 +71,22 @@ class CompiledModelWrap : public Napi::ObjectWrap { /** @brief Exports the compiled model to bytes/output stream. */ Napi::Value export_model(const Napi::CallbackInfo& info); + /** + * @brief Sets properties for current compiled model. + * @param info Contains information about the environment and passed arguments, + * this method accepts only one argument of type object. + * @return Napi::Undefined + */ + Napi::Value set_property(const Napi::CallbackInfo& info); + + /** + * @brief Gets property for current compiled model. + * @param info Contains information about the environment and passed arguments, + * this method accepts only one argument of type string. + * @return A Napi::Value + */ + Napi::Value get_property(const Napi::CallbackInfo& info); + private: /** @brief Gets node of a compiled model specified in CallbackInfo. */ Napi::Value get_node(const Napi::CallbackInfo& info, diff --git a/src/bindings/js/node/lib/addon.ts b/src/bindings/js/node/lib/addon.ts index 3c07b95455c5c6..a48ac06f9574de 100644 --- a/src/bindings/js/node/lib/addon.ts +++ b/src/bindings/js/node/lib/addon.ts @@ -301,6 +301,12 @@ interface CompiledModel { inputs: Output[]; /** It gets all outputs of a compiled model. */ outputs: Output[]; + /** + * It gets the property for the current compiled model. + * @param propertyName A string to get the property value. + * @returns The property value. + */ + getProperty(propertyName: string): string | number | boolean; /** * It creates an inference request object used to infer the compiled model. * @return {InferRequest} @@ -349,7 +355,15 @@ interface CompiledModel { * @returns {Output} A compiled model input. */ input(name: string): Output; - + /** + * It sets properties for the current compiled model. Properties + * can be retrieved via {@link CompiledModel.getProperty}. + * @param property An object with the key-value pairs. + * (property name, property value) + */ + setProperty(properties: { + [propertyName: string]: string | number | boolean + }): void; } /** diff --git a/src/bindings/js/node/src/compiled_model.cpp b/src/bindings/js/node/src/compiled_model.cpp index 495322dab15823..f9d13ddeb66d13 100644 --- a/src/bindings/js/node/src/compiled_model.cpp +++ b/src/bindings/js/node/src/compiled_model.cpp @@ -5,8 +5,10 @@ #include "node/include/addon.hpp" #include "node/include/errors.hpp" +#include "node/include/helper.hpp" #include "node/include/infer_request.hpp" #include "node/include/node_output.hpp" +#include "node/include/type_validation.hpp" CompiledModelWrap::CompiledModelWrap(const Napi::CallbackInfo& info) : Napi::ObjectWrap(info), @@ -20,7 +22,9 @@ Napi::Function CompiledModelWrap::get_class(Napi::Env env) { InstanceAccessor<&CompiledModelWrap::get_inputs>("inputs"), InstanceMethod("output", &CompiledModelWrap::get_output), InstanceAccessor<&CompiledModelWrap::get_outputs>("outputs"), - InstanceMethod("exportModelSync", &CompiledModelWrap::export_model)}); + InstanceMethod("exportModelSync", &CompiledModelWrap::export_model), + InstanceMethod("setProperty", &CompiledModelWrap::set_property), + InstanceMethod("getProperty", &CompiledModelWrap::get_property)}); } Napi::Object CompiledModelWrap::wrap(Napi::Env env, ov::CompiledModel compiled_model) { @@ -122,3 +126,36 @@ Napi::Value CompiledModelWrap::export_model(const Napi::CallbackInfo& info) { const auto& exported = _stream.str(); return Napi::Buffer::Copy(info.Env(), exported.c_str(), exported.size()); } + +Napi::Value CompiledModelWrap::set_property(const Napi::CallbackInfo& info) { + Napi::Env env = info.Env(); + std::vector allowed_signatures; + try { + if (ov::js::validate(info, allowed_signatures)) { + const auto properties = to_anyMap(env, info[0]); + _compiled_model.set_property(properties); + } else { + OPENVINO_THROW("'setProperty'", ov::js::get_parameters_error_msg(info, allowed_signatures)); + } + } catch (const std::exception& e) { + reportError(env, e.what()); + } + return env.Undefined(); +} + +Napi::Value CompiledModelWrap::get_property(const Napi::CallbackInfo& info) { + Napi::Env env = info.Env(); + std::vector allowed_signatures; + try { + if (ov::js::validate(info, allowed_signatures)) { + const auto property_name = info[0].As().Utf8Value(); + const auto property = _compiled_model.get_property(property_name); + return any_to_js(info, property); + } else { + OPENVINO_THROW("'getProperty'", ov::js::get_parameters_error_msg(info, allowed_signatures)); + } + } catch (const std::exception& e) { + reportError(env, e.what()); + } + return env.Undefined(); +} diff --git a/src/bindings/js/node/tests/unit/compiled_model.test.js b/src/bindings/js/node/tests/unit/compiled_model.test.js new file mode 100644 index 00000000000000..6b33296131b04d --- /dev/null +++ b/src/bindings/js/node/tests/unit/compiled_model.test.js @@ -0,0 +1,78 @@ +// -*- coding: utf-8 -*- +// Copyright (C) 2018-2024 Intel Corporation +// SPDX-License-Identifier: Apache-2.0 + +const { addon: ov } = require('../..'); +const assert = require('assert'); +const { describe, it } = require('node:test'); +const { getModelPath } = require('./utils.js'); + +const testXml = getModelPath().xml; +const core = new ov.Core(); +const properties = { + "AUTO_BATCH_TIMEOUT": '1' +}; +const compiledModel = core.compileModelSync(testXml, 'BATCH:CPU', properties); + +describe('setProperty() / getProperty()', () => { + + describe('getProperty()', () => { + it('returns the value of property from compiled model', () => { + assert.strictEqual(compiledModel.getProperty('AUTO_BATCH_TIMEOUT'), '1'); + }); + it('throws an error when called without arguments', () => { + assert.throws( + () => compiledModel.getProperty(), + /'getProperty' method called with incorrect parameters/ + ); + }); + it('throws an error when called with property name that does not exists', ()=>{ + assert.throws( + () => compiledModel.getProperty('PROPERTY_THAT_DOES_NOT_EXIST') + ); + }); + }); + + describe('setProperty()', () => { + it('sets a properties for compiled model', () => { + properties["AUTO_BATCH_TIMEOUT"] = '1000'; + assert.doesNotThrow(() => compiledModel.setProperty(properties)); + }); + + it('throws an error when called without an object argument', () => { + assert.throws( + () => compiledModel.setProperty(), + /'setProperty' method called with incorrect parameters/ + ); + }); + it('throws an error when called with wrong argument', () => { + assert.throws( + () => compiledModel.setProperty(123), + /'setProperty' method called with incorrect parameters/ + ); + }); + + it('throws an error when called with multiple arguments', () => { + assert.throws( + () => compiledModel.setProperty({"PERFORMANCE_HINT": "THROUGHPUT"}, {"NUM_STREAMS": "AUTO"}), + /'setProperty' method called with incorrect parameters/ + ); + }); + + it('returns the set property of the compiled model', () => { + properties["AUTO_BATCH_TIMEOUT"] = '123'; + compiledModel.setProperty(properties); + assert.strictEqual(compiledModel.getProperty('AUTO_BATCH_TIMEOUT'), 123); + }); + + it('retains the last set property when set multiple times', () => { + compiledModel.setProperty({"AUTO_BATCH_TIMEOUT": '321'}); + compiledModel.setProperty({'AUTO_BATCH_TIMEOUT': '132'}); + assert.strictEqual(compiledModel.getProperty('AUTO_BATCH_TIMEOUT'), 132); + }); + + it('allows to pass empty object', () => { + assert.doesNotThrow(() => compiledModel.setProperty({})); + }); + }); +});