diff --git a/packages/qvac-lib-inference-addon-onnx-ocr-fasttext/CMakeLists.txt b/packages/qvac-lib-inference-addon-onnx-ocr-fasttext/CMakeLists.txt index 559975ee37..2d3dab7db6 100644 --- a/packages/qvac-lib-inference-addon-onnx-ocr-fasttext/CMakeLists.txt +++ b/packages/qvac-lib-inference-addon-onnx-ocr-fasttext/CMakeLists.txt @@ -104,7 +104,7 @@ set(CMAKE_POSITION_INDEPENDENT_CODE ON) -find_path(QVAC_LIB_INFERENCE_ADDON_CPP_INCLUDE_DIRS "qvac-lib-inference-addon-cpp/Addon.hpp") +find_path(QVAC_LIB_INFERENCE_ADDON_CPP_INCLUDE_DIRS "qvac-lib-inference-addon-cpp/JsInterface.hpp") find_package(OpenCV REQUIRED) find_package(onnxruntime CONFIG REQUIRED) @@ -113,9 +113,7 @@ add_bare_module(qvac-lib-inference-addon-onnx-ocr-fasttext EXPORTS) target_sources( ${qvac-lib-inference-addon-onnx-ocr-fasttext} PRIVATE - addon/addon/Addon.cpp addon/js-interface/binding.cpp - addon/js-interface/qvac-lib-inference-addon-onnx-ocr-fasttext.cpp addon/pipeline/Lang.cpp addon/pipeline/Pipeline.cpp addon/pipeline/Steps.cpp diff --git a/packages/qvac-lib-inference-addon-onnx-ocr-fasttext/addon/addon/Addon.cpp b/packages/qvac-lib-inference-addon-onnx-ocr-fasttext/addon/addon/Addon.cpp deleted file mode 100644 index af940a18f5..0000000000 --- a/packages/qvac-lib-inference-addon-onnx-ocr-fasttext/addon/addon/Addon.cpp +++ /dev/null @@ -1,237 +0,0 @@ -#include "Addon.hpp" -#include -#include -#include -#include -#include "qvac-lib-inference-addon-cpp/Logger.hpp" - -// Specializations of Addon methods -namespace qvac_lib_inference_addon_cpp { - -/** - * @brief Construct a new qvac lib inference addon onnx ocr fasttext::Addon::Addon object - * - * @param env : JS environment handle - * @param pathDetector : path to the ONNX model containing the Detector - * @param pathRecognizer : path to the ONNX model containing the Recognizer - * @param langList : a list of languages to be supported by this model for text extraction - * @param jsHandle : JS object pointing to the addon handle in JS - * @param outputCb : JS function to be called on any inference event ( started, new output, error, etc ) - * @param transitionCb : JS function to be called on addon state changes (LISTENING, IDLE, STOPPED, etc) - */ -template <> -template <> -// NOLINTNEXTLINE(cppcoreguidelines-pro-type-member-init) -qvac_lib_inference_addon_onnx_ocr_fasttext::Addon::Addon( - js_env_t* env, const ORTCHAR_T* pathDetector, - const ORTCHAR_T* pathRecognizer, std::span langList, - bool useGPU, int timeout, qvac_lib_inference_addon_onnx_ocr_fasttext::PipelineConfig config, - js_value_t* jsThis, js_value_t* outputCallback, - js_value_t* transitionCallback) - : env_{env}, transitionCb_{transitionCallback}, - model_{pathDetector, pathRecognizer, langList, useGPU, timeout, config}, - jsHandle_{nullptr}, outputCb_{nullptr}, - jsOutputCallbackAsyncHandle_{nullptr}, threadsafeOutputCb_{nullptr} { - initializeProcessingThread(env, jsThis, outputCallback, transitionCallback); -} - -template<> -void qvac_lib_inference_addon_onnx_ocr_fasttext::Addon::process() { - static constexpr auto PROCESS_WAIT_MILLISECONDS = std::chrono::milliseconds{100}; - std::unique_ptr> currentJob; - auto reset = [&]() { - model_.reset(); - currentJob.reset(); - }; - - while (running_) { - std::unique_lock uniqueLock(mtx_); - processCv_.wait_for(uniqueLock, PROCESS_WAIT_MILLISECONDS); - - switch (signal_) { - case ProcessSignals::Activate: - status_ = AddonStatus::Processing; - break; - case ProcessSignals::Stop: - status_ = AddonStatus::Stopped; - reset(); - break; - case ProcessSignals::Pause: - status_ = AddonStatus::Paused; - break; - case ProcessSignals::Cancel: - if (currentJob && (cancelJobId_ == 0 || currentJob->id == cancelJobId_)) { - queueOutput(ModelOutput{ OutputEvent::JobEnded, currentJob->id, model_.runtimeStats() }); - reset(); - cancelJobId_ = 0; - } - break; - default: - break; - } - signal_ = ProcessSignals::None; - - if (status_ == AddonStatus::Stopped || status_ == AddonStatus::Paused || status_ == AddonStatus::Loading) { continue; } - - if (currentJob == nullptr) { - // get next job - if (jobQueue_.empty()) { - status_ = AddonStatus::Idle; - continue; - } - currentJob = std::move(jobQueue_.top().job); - jobQueue_.pop(); - status_ = AddonStatus::Processing; - queueOutput(ModelOutput{ OutputEvent::JobStarted, currentJob->id }); - } - - status_ = AddonStatus::Processing; - uniqueLock.unlock(); - - try { - auto output = model_.process(currentJob->input); - std::scoped_lock slk{mtx_}; - queueOutput(ModelOutput{ OutputEvent::Output, currentJob->id, std::move(output) }); - queueOutput(ModelOutput{ OutputEvent::JobEnded, currentJob->id, model_.runtimeStats() }); - reset(); - } catch (const std::exception& e) { - // Error, cancel current job - auto jobId = currentJob->id; - uniqueLock.lock(); - queueOutput(ModelOutput{ OutputEvent::Error, jobId, ModelOutput::Error{e.what()} }); - queueOutput(ModelOutput{ OutputEvent::JobEnded, jobId, model_.runtimeStats() }); - reset(); - } - } -} - -namespace { - -js_value_t* createArrayFromElements(js_env_t* env, std::span elements) { - js_value_t *jsArray = nullptr; - js_create_array_with_length(env, elements.size(), &jsArray); - js_set_array_elements(env, jsArray, const_cast(elements.data()), elements.size(), 0); - return jsArray; -} - -js_value_t* getJsArrayFromOutput(js_env_t* env, qvac_lib_inference_addon_onnx_ocr_fasttext::Pipeline::Output &inferredTextList) { - size_t inferredTextListLength = inferredTextList.size(); - auto jsInferredTextListElements = std::make_unique(inferredTextListLength); /* NOLINT(modernize-avoid-c-arrays,cppcoreguidelines-avoid-c-arrays,hicpp-avoid-c-arrays) */ - - // Populate each element of jsInferredTextListElements with an inferredText array: [bounding box, text, confidence] - for (size_t i = 0; i < inferredTextListLength; i++) { - - // Create bounding box elements: [ [x1, y1], [x2, y2], [x3, y3], [x4, y4 ] - constexpr size_t BOX_COORDINATES_LENGTH = 4; - std::array jsBoxCoordinatesElements{}; - for (size_t boxCoordinateIndex = 0; boxCoordinateIndex < BOX_COORDINATES_LENGTH; boxCoordinateIndex++) { - constexpr size_t COORDINATE_PAIR_LENGTH = 2; - std::array jsCoordinatePairElement{}; - jsCoordinatePairElement.at(0) = js::Number::create(env, inferredTextList[i].boxCoordinates.at(boxCoordinateIndex).x); - jsCoordinatePairElement.at(1) = js::Number::create(env, inferredTextList[i].boxCoordinates.at(boxCoordinateIndex).y); - jsBoxCoordinatesElements.at(boxCoordinateIndex) = createArrayFromElements(env, std::span{jsCoordinatePairElement}); - } - - constexpr size_t INFERRED_TEXT_LENGTH = 3; - std::array jsInferredTextElements{}; - jsInferredTextElements.at(0) = createArrayFromElements(env, std::span{jsBoxCoordinatesElements}); - jsInferredTextElements.at(1) = js::String::create(env, inferredTextList[i].text); - jsInferredTextElements.at(2) = js::Number::create(env, inferredTextList[i].confidenceScore); - - jsInferredTextListElements[i] = createArrayFromElements(env, std::span{jsInferredTextElements}); - } - - return createArrayFromElements(env, std::span{jsInferredTextListElements.get(), inferredTextListLength}); -} - -} - -template<> -void qvac_lib_inference_addon_onnx_ocr_fasttext::Addon::jsOutputCallback(uv_async_t* handle) try { - auto& addon = *reinterpret_cast /* NOLINT(cppcoreguidelines-pro-type-reinterpret-cast) */(uv_handle_get_data(reinterpret_cast /* NOLINT(cppcoreguidelines-pro-type-reinterpret-cast) */(handle))); - js_handle_scope_t* scope = nullptr; - JS(js_open_handle_scope(addon.env_, &scope)); - auto scopeCleanup = utils::onExit([env=addon.env_, scope]() { js_close_handle_scope(env, scope); }); - js_value_t* outputCb = nullptr; - JS(js_get_reference_value(addon.env_, addon.outputCb_, &outputCb)); - js_value_t* jsHandle = nullptr; - JS(js_get_reference_value(addon.env_, addon.jsHandle_, &jsHandle)); - std::vector outputQueue; - { - std::scoped_lock scopedLock{ addon.mtx_ }; - outputQueue = std::move(addon.outputQueue_); - } - for (auto& output : outputQueue) { - js_handle_scope_t* innerScope = nullptr; - JS(js_open_handle_scope(addon.env_, &innerScope)); - auto scopeCleanup = utils::onExit([env = addon.env_, innerScope]() { js_close_handle_scope(env, innerScope); }); - static constexpr size_t OUTPUT_CB_PARAMETERS_COUNT = 5; - std::array outputCbParameters{ - jsHandle, - js::String::create(addon.env_, outputEventToStringView(output.event) ), - js::Number::create(addon.env_, output.id) - , nullptr, - nullptr - }; - switch (output.event) { - case OutputEvent::Output: { - auto& inferredTextList = std::get(output.data); - outputCbParameters[3] = getJsArrayFromOutput(addon.env_, inferredTextList); - outputCbParameters[4] = js::Undefined::create(addon.env_); - } break; - case OutputEvent::JobStarted: { - outputCbParameters[3] = js::Undefined::create(addon.env_); - outputCbParameters[4] = js::Undefined::create(addon.env_); - } break; - case OutputEvent::JobEnded: { - js::Object runtimeStats = js::Object::create(addon.env_); - auto& stats = std::get(output.data); - - for (auto& statPair : stats) { - std::visit([env=addon.env_, &runtimeStats, &statPair](auto&& val) { - runtimeStats.setProperty( env, statPair.first.c_str(), js::Number::create(env, val) ); - }, statPair.second); - } - outputCbParameters[3] = runtimeStats; - outputCbParameters[4] = js::Undefined::create(addon.env_); - } break; - case OutputEvent::Error: { - outputCbParameters[3] = js::Undefined::create(addon.env_); - outputCbParameters[4] = js::String::create(addon.env_, std::get(output.data).error); - } break; - default: { throw std::logic_error("Unhandled OutputEvent"); } - } - js_value_t* receiver = nullptr; - JS(js_get_global(addon.env_, &receiver)); - JS(js_call_function(addon.env_, receiver, outputCb, OUTPUT_CB_PARAMETERS_COUNT, outputCbParameters.data(), nullptr)); - } -} catch (...) { - auto& addon = *reinterpret_cast /* NOLINT(cppcoreguidelines-pro-type-reinterpret-cast) */(uv_handle_get_data(reinterpret_cast /* NOLINT(cppcoreguidelines-pro-type-reinterpret-cast) */(handle))); - js_handle_scope_t* scope = nullptr; - if (js_open_handle_scope(addon.env_, &scope) != 0) { return; } - auto scopeCleanup = utils::onExit([env = addon.env_, scope]() { js_close_handle_scope(env, scope); }); - bool isExceptionPending = false; - if (js_is_exception_pending(addon.env_, &isExceptionPending) != 0) { return; } - if (isExceptionPending) { - js_value_t* error = nullptr; - js_get_and_clear_last_exception(addon.env_, &error); - } - QLOG(qvac_lib_inference_addon_cpp::logger::Priority::ERROR, "jsOutputCallback : failed"); -} - -template<> -uint32_t qvac_lib_inference_addon_onnx_ocr_fasttext::Addon::append(int priority, qvac_lib_inference_addon_onnx_ocr_fasttext::PipelineInput input) { - uint32_t jobId = 0; - { - std::scoped_lock lock{ mtx_ }; - auto newJob = std::make_unique>(++jobIds_); - jobId = newJob->id; - newJob->input = std::move(input); - static constexpr int DEFAULT_PRIORITY = 50; - jobQueue_.emplace(priority == -1? DEFAULT_PRIORITY : priority, std::move(newJob)); - } - processCv_.notify_one(); - return jobId; -} - -} diff --git a/packages/qvac-lib-inference-addon-onnx-ocr-fasttext/addon/addon/Addon.hpp b/packages/qvac-lib-inference-addon-onnx-ocr-fasttext/addon/addon/Addon.hpp deleted file mode 100644 index 19a314c79c..0000000000 --- a/packages/qvac-lib-inference-addon-onnx-ocr-fasttext/addon/addon/Addon.hpp +++ /dev/null @@ -1,21 +0,0 @@ -#pragma once - -#include "qvac-lib-inference-addon-cpp/Addon.hpp" -#include "pipeline/Pipeline.hpp" - -namespace qvac_lib_inference_addon_cpp { - template<> - void Addon::jsOutputCallback(uv_async_t* handle); - - template<> - uint32_t Addon::append(int priority, qvac_lib_inference_addon_onnx_ocr_fasttext::PipelineInput input); - - template<> - void Addon::process(); -} - -namespace qvac_lib_inference_addon_onnx_ocr_fasttext { - -using Addon = qvac_lib_inference_addon_cpp::Addon; - -} diff --git a/packages/qvac-lib-inference-addon-onnx-ocr-fasttext/addon/addon/AddonCpp.hpp b/packages/qvac-lib-inference-addon-onnx-ocr-fasttext/addon/addon/AddonCpp.hpp new file mode 100644 index 0000000000..cbcdf5d9ac --- /dev/null +++ b/packages/qvac-lib-inference-addon-onnx-ocr-fasttext/addon/addon/AddonCpp.hpp @@ -0,0 +1,47 @@ +#pragma once + +#include + +#include +#include +#include +#include +#include + +#include "pipeline/Pipeline.hpp" + +namespace qvac_lib_inference_addon_onnx_ocr_fasttext { + +struct AddonInstance { + std::unique_ptr addon; + std::shared_ptr> + outputHandler; +}; + +/// @brief Creates a pure C++ Addon (no Js dependencies). Can be used on CLI or +/// C++ tests. +inline AddonInstance createInstance( + const ORTCHAR_T* pathDetector, const ORTCHAR_T* pathRecognizer, + std::span langList, bool useGPU = true, + int timeout = Pipeline::DEFAULT_PIPELINE_TIMEOUT_SECONDS, + const Pipeline::Config& config = Pipeline::Config{}) { + using namespace qvac_lib_inference_addon_cpp; + using namespace std; + + auto model = make_unique( + pathDetector, pathRecognizer, langList, useGPU, timeout, config); + + auto outHandler = + make_shared>(); + out_handl::OutputHandlers> + outHandlers; + outHandlers.add(outHandler); + unique_ptr callback = + make_unique(std::move(outHandlers)); + + auto addon = make_unique(std::move(callback), std::move(model)); + + return {std::move(addon), std::move(outHandler)}; +} +} // namespace qvac_lib_inference_addon_onnx_ocr_fasttext diff --git a/packages/qvac-lib-inference-addon-onnx-ocr-fasttext/addon/addon/AddonJs.hpp b/packages/qvac-lib-inference-addon-onnx-ocr-fasttext/addon/addon/AddonJs.hpp new file mode 100644 index 0000000000..3e3d203522 --- /dev/null +++ b/packages/qvac-lib-inference-addon-onnx-ocr-fasttext/addon/addon/AddonJs.hpp @@ -0,0 +1,281 @@ +#pragma once +#include +#include +#include + +#include +#include +#include +#include +#include +#include +#include +#include + +#include "pipeline/Pipeline.hpp" +#include "pipeline/Steps.hpp" + +namespace qvac_lib_inference_addon_onnx_ocr_fasttext { + +namespace { +js_value_t* +createArrayFromElements(js_env_t* env, std::span elements) { + js_value_t* jsArray = nullptr; + js_create_array_with_length(env, elements.size(), &jsArray); + js_set_array_elements( + env, + jsArray, + const_cast(elements.data()), + elements.size(), + 0); + return jsArray; +} + +js_value_t* +getJsArrayFromOutput(js_env_t* env, const Pipeline::Output& inferredTextList) { + size_t inferredTextListLength = inferredTextList.size(); + auto jsInferredTextListElements = std::make_unique( + inferredTextListLength); /* NOLINT(modernize-avoid-c-arrays,cppcoreguidelines-avoid-c-arrays,hicpp-avoid-c-arrays) + */ + + // Populate each element of jsInferredTextListElements with an inferredText + // array: [bounding box, text, confidence] + for (size_t i = 0; i < inferredTextListLength; i++) { + + // Create bounding box elements: [ [x1, y1], [x2, y2], [x3, y3], [x4, y4 ] + constexpr size_t BOX_COORDINATES_LENGTH = 4; + std::array jsBoxCoordinatesElements{}; + for (size_t boxCoordinateIndex = 0; + boxCoordinateIndex < BOX_COORDINATES_LENGTH; + boxCoordinateIndex++) { + constexpr size_t COORDINATE_PAIR_LENGTH = 2; + std::array jsCoordinatePairElement{}; + jsCoordinatePairElement.at(0) = + qvac_lib_inference_addon_cpp::js::Number::create( + env, inferredTextList[i].boxCoordinates.at(boxCoordinateIndex).x); + jsCoordinatePairElement.at(1) = + qvac_lib_inference_addon_cpp::js::Number::create( + env, inferredTextList[i].boxCoordinates.at(boxCoordinateIndex).y); + jsBoxCoordinatesElements.at(boxCoordinateIndex) = + createArrayFromElements(env, std::span{jsCoordinatePairElement}); + } + + constexpr size_t INFERRED_TEXT_LENGTH = 3; + std::array jsInferredTextElements{}; + jsInferredTextElements.at(0) = + createArrayFromElements(env, std::span{jsBoxCoordinatesElements}); + jsInferredTextElements.at(1) = + qvac_lib_inference_addon_cpp::js::String::create( + env, inferredTextList[i].text); + jsInferredTextElements.at(2) = + qvac_lib_inference_addon_cpp::js::Number::create( + env, inferredTextList[i].confidenceScore); + + jsInferredTextListElements[i] = + createArrayFromElements(env, std::span{jsInferredTextElements}); + } + + return createArrayFromElements( + env, + std::span{ + jsInferredTextListElements.get(), inferredTextListLength}); +} +} // namespace + +// Custom output handler for Pipeline::Output +class PipelineOutputHandler + : public qvac_lib_inference_addon_cpp::out_handl::JsOutputHandlerInterface { +public: + void setEnv(js_env_t* env) override { env_ = env; } + + js_value_t* handleOutput(const std::any& output) const override { + if (output.type() != typeid(Pipeline::Output)) { + throw std::runtime_error("PipelineOutputHandler: unexpected data type"); + } + const auto& pipelineOutput = std::any_cast(output); + return getJsArrayFromOutput(env_, pipelineOutput); + } + + bool canHandle(const std::any& input) const override { + return input.type() == typeid(Pipeline::Output); + } + +private: + js_env_t* env_ = nullptr; +}; + +namespace { +auto getPath(js_env_t* env, qvac_lib_inference_addon_cpp::js::String path) { + if constexpr (std::is_same_v) { + return path.as(env); + } else if constexpr ( + std::is_same_v && sizeof(wchar_t) == 2) { + size_t length = 0; + JS(js_get_value_string_utf16le(env, path, nullptr, 0, &length)); + std::wstring str(length, '\0'); + JS(js_get_value_string_utf16le( + env, + path, + reinterpret_cast( + str.data()) /* NOLINT(cppcoreguidelines-pro-type-reinterpret-cast) + */ + , + length, + nullptr)); + return str; + } +} +} // namespace + +inline js_value_t* createInstance(js_env_t* env, js_callback_info_t* info) try { + using namespace qvac_lib_inference_addon_cpp; + using namespace std; + + auto args = js::getArguments(env, info); + if (args.size() != 4) { + throw StatusError{ + general_error::InvalidArgument, + "Incorrect number of parameters. Expected 4 parameters"}; + } + if (!js::is(env, args[1])) { + throw StatusError{ + general_error::InvalidArgument, + "Expected configurationParams as object"}; + } + if (!js::is(env, args[2])) { + throw StatusError{ + general_error::InvalidArgument, "Expected output callback as function"}; + } + auto args1 = js::Object::fromValue(args[1]); + auto pathDetector = + getPath(env, args1.getProperty(env, "pathDetector")); + auto pathRecognizer = + getPath(env, args1.getProperty(env, "pathRecognizer")); + auto langList = js::toVector( + env, args1.getProperty(env, "langList")); + auto optUseGPU = args1.getOptionalProperty(env, "useGPU"); + bool useGPU = optUseGPU ? optUseGPU->as(env) : true; + auto optTimeout = args1.getOptionalProperty(env, "timeout"); + int timeout = optTimeout ? static_cast(optTimeout->as(env)) + : DEFAULT_PIPELINE_TIMEOUT_SECONDS; + + // Parse optional config parameters + Pipeline::Config config; + + auto optMagRatio = args1.getOptionalProperty(env, "magRatio"); + if (optMagRatio) { + config.magRatio = static_cast(optMagRatio->as(env)); + } + + auto optDefaultRotationAngles = + args1.getOptionalProperty(env, "defaultRotationAngles"); + if (optDefaultRotationAngles) { + config.defaultRotationAngles = + js::toVector(env, *optDefaultRotationAngles); + } + + auto optContrastRetry = + args1.getOptionalProperty(env, "contrastRetry"); + if (optContrastRetry) { + config.contrastRetry = optContrastRetry->as(env); + } + + auto optLowConfidenceThreshold = + args1.getOptionalProperty(env, "lowConfidenceThreshold"); + if (optLowConfidenceThreshold) { + config.lowConfidenceThreshold = + static_cast(optLowConfidenceThreshold->as(env)); + } + + auto optRecognizerBatchSize = + args1.getOptionalProperty(env, "recognizerBatchSize"); + if (optRecognizerBatchSize) { + config.recognizerBatchSize = + static_cast(optRecognizerBatchSize->as(env)); + } + + auto model = make_unique( + pathDetector.c_str(), + pathRecognizer.c_str(), + std::span(langList), + useGPU, + timeout, + config); + + out_handl::OutputHandlers outHandlers; + outHandlers.add(make_shared()); + unique_ptr callback = make_unique( + env, args[0], args[2], args[3], std::move(outHandlers)); + + auto addon = make_unique(env, std::move(callback), std::move(model)); + + return JsInterface::createInstance(env, std::move(addon)); +} +JSCATCH + +inline js_value_t* runJob(js_env_t* env, js_callback_info_t* info) try { + using namespace qvac_lib_inference_addon_cpp; + using namespace std; + + auto args = js::getArguments(env, info); + if (args.size() != 2) { + throw StatusError{general_error::InvalidArgument, "Expected 2 parameters"}; + } + if (!js::is(env, args[1])) { + throw StatusError{general_error::InvalidArgument, "Expected Object"}; + } + auto args1 = js::Object::fromValue(args[1]); + auto type = args1.getProperty(env, "type").as(env); + + if (type == "image") { + Pipeline::Input modelInput; + + auto input = args1.getProperty(env, "input"); + + // Check if this is an encoded image (JPEG/PNG) that needs decoding + auto isEncoded = input.getOptionalProperty(env, "isEncoded"); + if (isEncoded && isEncoded->as(env)) { + modelInput.isEncoded = true; + modelInput.data = input.getProperty>(env, "data") + .as>(env); + } else { + modelInput.isEncoded = false; + modelInput.imageWidth = + input.getProperty(env, "width").as(env); + modelInput.imageHeight = + input.getProperty(env, "height").as(env); + modelInput.data = input.getProperty>(env, "data") + .as>(env); + } + + auto options = args1.getOptionalProperty(env, "options"); + if (options) { + auto paragraph = + options->getOptionalProperty(env, "paragraph"); + if (paragraph) { + modelInput.paragraph = paragraph->as(env); + } + + auto boxMarginMultiplier = + options->getOptionalProperty(env, "boxMarginMultiplier"); + if (boxMarginMultiplier) { + modelInput.boxMarginMultiplier = + static_cast(boxMarginMultiplier->as(env)); + } + + auto rotationAngles = + options->getOptionalProperty(env, "rotationAngles"); + if (rotationAngles) { + modelInput.rotationAngles = + js::toVector(env, *rotationAngles); + } + } + + JsInterface::getInstance(env, args[0]).addonCpp->runJob(std::any(std::move(modelInput))); + return nullptr; + } + throw StatusError{general_error::InvalidArgument, "Invalid type"}; +} +JSCATCH + +} // namespace qvac_lib_inference_addon_onnx_ocr_fasttext diff --git a/packages/qvac-lib-inference-addon-onnx-ocr-fasttext/addon/js-interface/binding.cpp b/packages/qvac-lib-inference-addon-onnx-ocr-fasttext/addon/js-interface/binding.cpp index cf744b5305..d6ae8247c9 100644 --- a/packages/qvac-lib-inference-addon-onnx-ocr-fasttext/addon/js-interface/binding.cpp +++ b/packages/qvac-lib-inference-addon-onnx-ocr-fasttext/addon/js-interface/binding.cpp @@ -1,33 +1,33 @@ #include -#include -#include "qvac-lib-inference-addon-onnx-ocr-fasttext.hpp" +#include "../addon/AddonJs.hpp" -js_value_t* qvacLibInferenceAddonOnnxOcrFasttextExports(js_env_t *env, js_value_t *exports) { +js_value_t* qvacLibInferenceAddonOnnxOcrFasttextExports( + js_env_t* env, + js_value_t* exports) { // NOLINT(readability-identifier-naming) // NOLINTBEGIN(cppcoreguidelines-macro-usage) -#define V(name, fn) \ - { \ - js_value_t *val; \ - if ( js_create_function(env, name, -1, fn, nullptr, &val) != 0) { \ - return nullptr; \ - } \ - if ( js_set_named_property(env, exports, name, val) != 0) { \ - return nullptr; \ - } \ +#define V(name, fn) \ + { \ + js_value_t* val; \ + if (js_create_function(env, name, -1, fn, nullptr, &val) != 0) { \ + return nullptr; \ + } \ + if (js_set_named_property(env, exports, name, val) != 0) { \ + return nullptr; \ + } \ } V("createInstance", qvac_lib_inference_addon_onnx_ocr_fasttext::createInstance) - V("loadWeights", qvac_lib_inference_addon_onnx_ocr_fasttext::loadWeights) - V("activate", qvac_lib_inference_addon_onnx_ocr_fasttext::activate) - V("append", qvac_lib_inference_addon_onnx_ocr_fasttext::append) - V("status", qvac_lib_inference_addon_onnx_ocr_fasttext::status) - V("pause", qvac_lib_inference_addon_onnx_ocr_fasttext::pause) - V("stop", qvac_lib_inference_addon_onnx_ocr_fasttext::stop) - V("cancel", qvac_lib_inference_addon_onnx_ocr_fasttext::cancel) - V("destroyInstance", qvac_lib_inference_addon_onnx_ocr_fasttext::destroyInstance) - V("setLogger", qvac_lib_inference_addon_onnx_ocr_fasttext::setLogger) - V("releaseLogger", qvac_lib_inference_addon_onnx_ocr_fasttext::releaseLogger) + V("runJob", qvac_lib_inference_addon_onnx_ocr_fasttext::runJob) + + V("loadWeights", qvac_lib_inference_addon_cpp::JsInterface::loadWeights) + V("activate", qvac_lib_inference_addon_cpp::JsInterface::activate) + V("cancel", qvac_lib_inference_addon_cpp::JsInterface::cancel) + V("destroyInstance", + qvac_lib_inference_addon_cpp::JsInterface::destroyInstance) + V("setLogger", qvac_lib_inference_addon_cpp::JsInterface::setLogger) + V("releaseLogger", qvac_lib_inference_addon_cpp::JsInterface::releaseLogger) #undef V // NOLINTEND(cppcoreguidelines-macro-usage) diff --git a/packages/qvac-lib-inference-addon-onnx-ocr-fasttext/addon/js-interface/qvac-lib-inference-addon-onnx-ocr-fasttext.cpp b/packages/qvac-lib-inference-addon-onnx-ocr-fasttext/addon/js-interface/qvac-lib-inference-addon-onnx-ocr-fasttext.cpp deleted file mode 100644 index 0353469264..0000000000 --- a/packages/qvac-lib-inference-addon-onnx-ocr-fasttext/addon/js-interface/qvac-lib-inference-addon-onnx-ocr-fasttext.cpp +++ /dev/null @@ -1,214 +0,0 @@ -#include "qvac-lib-inference-addon-onnx-ocr-fasttext.hpp" - -#include "addon/Addon.hpp" -#include "qvac-lib-inference-addon-cpp/JsInterface.hpp" - -using JsIfFasttext = qvac_lib_inference_addon_cpp::JsInterface; - -// Specialization of JsInterface methods for Pipeline addon -namespace qvac_lib_inference_addon_cpp { - -namespace { - -qvac_lib_inference_addon_onnx_ocr_fasttext::Pipeline::InputView getModelInput(js_env_t *env, js::Object args1) { - qvac_lib_inference_addon_onnx_ocr_fasttext::Pipeline::InputView modelInput; - - auto input = args1.getProperty(env, "input"); - - // Check if this is an encoded image (JPEG/PNG) that needs decoding - auto isEncoded = input.getOptionalProperty(env, "isEncoded"); - if (isEncoded && isEncoded->as(env)) { - // Encoded image - only data is required, width/height will be determined after decoding - modelInput.isEncoded = true; - modelInput.data = input.getProperty>(env, "data").as>(env); - } else { - // Raw image data - requires width, height, and data - modelInput.isEncoded = false; - modelInput.imageWidth = input.getProperty(env, "width").as(env); - modelInput.imageHeight = input.getProperty(env, "height").as(env); - modelInput.data = input.getProperty>(env, "data").as>(env); - } - - auto options = args1.getOptionalProperty(env, "options"); - if (options) { - auto paragraph = options->getOptionalProperty(env, "paragraph"); - if (paragraph) { - modelInput.paragraph = paragraph->as(env); - } - - auto boxMarginMultiplier = options->getOptionalProperty(env, "boxMarginMultiplier"); - if (boxMarginMultiplier) { - modelInput.boxMarginMultiplier = static_cast(boxMarginMultiplier->as(env)); - } - - auto rotationAngles = options->getOptionalProperty(env, "rotationAngles"); - if (rotationAngles) { - modelInput.rotationAngles = js::toVector(env, *rotationAngles); - } - } - - return modelInput; -} - -auto getPath(js_env_t* env, js::String path) { - if constexpr (std::is_same_v) { - return path.as(env); - } else if constexpr (std::is_same_v && sizeof(wchar_t) == 2) { - size_t length = 0; - JS(js_get_value_string_utf16le(env, path, nullptr, 0, &length)); - std::wstring str(length, '\0'); - JS(js_get_value_string_utf16le(env, path, reinterpret_cast(str.data()) /* NOLINT(cppcoreguidelines-pro-type-reinterpret-cast) */, length, nullptr)); - return str; - } -} - -} // namespace - -template <> js_value_t *JsIfFasttext::createInstance(js_env_t *env, js_callback_info_t *info) try { - auto args = js::getArguments(env, info); - if (args.size() != 4) { - throw StatusError{ - general_error::InvalidArgument, - "Incorrect number of parameters. Expected 4 parameters"}; - } - if (!js::is(env, args[1])) { - throw StatusError{ - general_error::InvalidArgument, - "Expected configurationParams as object"}; - } - if (!js::is(env, args[2])) { - throw StatusError{ - general_error::InvalidArgument, "Expected output callback as function"}; - } - auto args1 = js::Object::fromValue(args[1]); - auto pathDetector = getPath(env, args1.getProperty(env, "pathDetector")); - auto pathRecognizer = getPath(env, args1.getProperty(env, "pathRecognizer")); - auto langList = js::toVector(env, args1.getProperty(env, "langList")); - auto optUseGPU = args1.getOptionalProperty(env, "useGPU"); - bool useGPU = optUseGPU ? optUseGPU->as(env) : true; - auto optTimeout = args1.getOptionalProperty(env, "timeout"); - int timeout = optTimeout ? optTimeout->as(env) : qvac_lib_inference_addon_onnx_ocr_fasttext::DEFAULT_PIPELINE_TIMEOUT_SECONDS; - - // Parse optional config parameters - qvac_lib_inference_addon_onnx_ocr_fasttext::PipelineConfig config; - - auto optMagRatio = args1.getOptionalProperty(env, "magRatio"); - if (optMagRatio) { - config.magRatio = static_cast(optMagRatio->as(env)); - } - - auto optDefaultRotationAngles = args1.getOptionalProperty(env, "defaultRotationAngles"); - if (optDefaultRotationAngles) { - config.defaultRotationAngles = js::toVector(env, *optDefaultRotationAngles); - } - - auto optContrastRetry = args1.getOptionalProperty(env, "contrastRetry"); - if (optContrastRetry) { - config.contrastRetry = optContrastRetry->as(env); - } - - auto optLowConfidenceThreshold = args1.getOptionalProperty(env, "lowConfidenceThreshold"); - if (optLowConfidenceThreshold) { - config.lowConfidenceThreshold = static_cast(optLowConfidenceThreshold->as(env)); - } - - auto optRecognizerBatchSize = args1.getOptionalProperty(env, "recognizerBatchSize"); - if (optRecognizerBatchSize) { - config.recognizerBatchSize = static_cast(optRecognizerBatchSize->as(env)); - } - - std::scoped_lock instancesLock{instancesMtx_}; - auto& handle = instances_.emplace_back( - std::make_unique( - env, - pathDetector.c_str(), - pathRecognizer.c_str(), - std::span(langList), - useGPU, - timeout, - config, - args[0], - args[2], - args[3])); - return js::External::create(env, handle.get()); -} -JSCATCH - -template <> js_value_t *JsIfFasttext::loadWeights(js_env_t *env, js_callback_info_t *info) try { - (void)info; throw std::logic_error{"loadWeights not supported"}; -} -JSCATCH - -template <> js_value_t *JsIfFasttext::append(js_env_t *env, js_callback_info_t *info) try { - auto args = js::getArguments(env, info); - if (args.size() != 2) { - throw StatusError{general_error::InvalidArgument, "Expected 2 parameters"}; - } - if (!js::is(env, args[1])) { - throw StatusError{general_error::InvalidArgument, "Expected Object"}; - } - auto args1 = js::Object::fromValue(args[1]); - auto type = args1.getProperty(env, "type").as(env); - - auto &instance = getInstance(env, args[0]); - - if (type == "image") { - auto priority = getAppendPriority(env, args1); - - qvac_lib_inference_addon_onnx_ocr_fasttext::Pipeline::InputView modelInput = getModelInput(env, args1); - - return js::Number::create(env, instance.append(priority, modelInput)); - } - throw StatusError{general_error::InvalidArgument, "Invalid type"}; -} -JSCATCH - -} // namespace qvac_lib_inference_addon_cpp - -namespace qvac_lib_inference_addon_onnx_ocr_fasttext { - -js_value_t *createInstance(js_env_t *env, js_callback_info_t *info) { - return JsIfFasttext::createInstance(env, info); -} - -js_value_t *loadWeights(js_env_t *env, js_callback_info_t *info) { - return JsIfFasttext::loadWeights(env, info); -} - -js_value_t *activate(js_env_t *env, js_callback_info_t *info) { - return JsIfFasttext::activate(env, info); -} - -js_value_t *append(js_env_t *env, js_callback_info_t *info) { - return JsIfFasttext::append(env, info); -} - -js_value_t *status(js_env_t *env, js_callback_info_t *info) { - return JsIfFasttext::status(env, info); -} - -js_value_t *pause(js_env_t *env, js_callback_info_t *info) { - return JsIfFasttext::pause(env, info); -} - -js_value_t *stop(js_env_t *env, js_callback_info_t *info) { - return JsIfFasttext::stop(env, info); -} - -js_value_t *cancel(js_env_t *env, js_callback_info_t *info) { - return JsIfFasttext::cancel(env, info); -} - -js_value_t *destroyInstance(js_env_t *env, js_callback_info_t *info) { - return JsIfFasttext::destroyInstance(env, info); -} - -js_value_t *setLogger(js_env_t *env, js_callback_info_t *info) { - return JsIfFasttext::setLogger(env, info); -} - -js_value_t *releaseLogger(js_env_t *env, js_callback_info_t *info) { - return JsIfFasttext::releaseLogger(env, info); -} - -} // namespace qvac_lib_inference_addon_onnx_ocr_fasttext diff --git a/packages/qvac-lib-inference-addon-onnx-ocr-fasttext/addon/js-interface/qvac-lib-inference-addon-onnx-ocr-fasttext.hpp b/packages/qvac-lib-inference-addon-onnx-ocr-fasttext/addon/js-interface/qvac-lib-inference-addon-onnx-ocr-fasttext.hpp index ef139d4b71..58243a7543 100644 --- a/packages/qvac-lib-inference-addon-onnx-ocr-fasttext/addon/js-interface/qvac-lib-inference-addon-onnx-ocr-fasttext.hpp +++ b/packages/qvac-lib-inference-addon-onnx-ocr-fasttext/addon/js-interface/qvac-lib-inference-addon-onnx-ocr-fasttext.hpp @@ -5,15 +5,5 @@ namespace qvac_lib_inference_addon_onnx_ocr_fasttext { js_value_t* createInstance(js_env_t* env, js_callback_info_t* info); -js_value_t* loadWeights(js_env_t* env, js_callback_info_t* info); -js_value_t* activate(js_env_t* env, js_callback_info_t* info); -js_value_t* append(js_env_t* env, js_callback_info_t* info); -js_value_t* status(js_env_t* env, js_callback_info_t* info); -js_value_t* pause(js_env_t* env, js_callback_info_t* info); -js_value_t* stop(js_env_t* env, js_callback_info_t* info); -js_value_t* cancel(js_env_t* env, js_callback_info_t* info); -js_value_t* destroyInstance(js_env_t* env, js_callback_info_t* info); -js_value_t* setLogger(js_env_t* env, js_callback_info_t* info); -js_value_t* releaseLogger(js_env_t* env, js_callback_info_t* info); - +js_value_t* runJob(js_env_t* env, js_callback_info_t* info); } diff --git a/packages/qvac-lib-inference-addon-onnx-ocr-fasttext/addon/pipeline/Pipeline.cpp b/packages/qvac-lib-inference-addon-onnx-ocr-fasttext/addon/pipeline/Pipeline.cpp index 920c1d693f..57f353b5c6 100644 --- a/packages/qvac-lib-inference-addon-onnx-ocr-fasttext/addon/pipeline/Pipeline.cpp +++ b/packages/qvac-lib-inference-addon-onnx-ocr-fasttext/addon/pipeline/Pipeline.cpp @@ -1,14 +1,17 @@ #include "Pipeline.hpp" #include -#include #include +#include #include #include + #include #include -#include "qvac-lib-inference-addon-cpp/Logger.hpp" + #include "AndroidLog.hpp" +#include "qvac-lib-inference-addon-cpp/Errors.hpp" +#include "qvac-lib-inference-addon-cpp/Logger.hpp" namespace qvac_lib_inference_addon_onnx_ocr_fasttext { @@ -73,21 +76,20 @@ Pipeline::Pipeline( ALOG_INFO(anglesMsg); } -Pipeline::Output Pipeline::process( - Pipeline::Input input, - std::function callback) { - auto output = process(std::move(input)); - if (callback) { - callback(output); +std::any Pipeline::process(const std::any& input) { + if (input.type() != typeid(Input)) { + throw qvac_errors::StatusError( + qvac_errors::general_error::InvalidArgument, + "Pipeline::process: unsupported input type"); } - return output; + return process(std::any_cast(input)); } void Pipeline::initializeBackend() { // No initialization needed for sequential pipeline } -bool Pipeline::isLoaded() { +bool Pipeline::isLoaded() const { return stepDetection_ && stepBoundingBox_ && stepRecognition_; } @@ -191,7 +193,7 @@ void Pipeline::reset() { // No state to reset in sequential pipeline } -qvac_lib_inference_addon_cpp::RuntimeStats Pipeline::runtimeStats() { +qvac_lib_inference_addon_cpp::RuntimeStats Pipeline::runtimeStats() const { double lastProcessingTime = 0; double lastDetectionTime = 0; double lastRecognitionTime = 0; diff --git a/packages/qvac-lib-inference-addon-onnx-ocr-fasttext/addon/pipeline/Pipeline.hpp b/packages/qvac-lib-inference-addon-onnx-ocr-fasttext/addon/pipeline/Pipeline.hpp index a021ebfb64..538768f044 100644 --- a/packages/qvac-lib-inference-addon-onnx-ocr-fasttext/addon/pipeline/Pipeline.hpp +++ b/packages/qvac-lib-inference-addon-onnx-ocr-fasttext/addon/pipeline/Pipeline.hpp @@ -1,19 +1,21 @@ #pragma once -#include "Steps.hpp" -#include "StepDetectionInference.hpp" -#include "StepBoundingBox.hpp" -#include "StepRecognizeText.hpp" - -#include - +#include #include #include #include -#include #include +#include #include +#include +#include + +#include "StepBoundingBox.hpp" +#include "StepDetectionInference.hpp" +#include "StepRecognizeText.hpp" +#include "Steps.hpp" + namespace qvac_lib_inference_addon_onnx_ocr_fasttext { // add_margin in python @@ -62,46 +64,71 @@ struct PipelineInput { * This is simpler and more reliable than a multi-threaded approach since each step * depends on the previous step's output anyway. */ -class Pipeline { - public: - using Input = PipelineInput; - using InputView = PipelineInput; - using Output = std::vector; - using Config = PipelineConfig; +class Pipeline : public qvac_lib_inference_addon_cpp::model::IModel, + public qvac_lib_inference_addon_cpp::model::IModelAsyncLoad, + public qvac_lib_inference_addon_cpp::model::IModelCancel { +public: + using Input = PipelineInput; + using InputView = PipelineInput; + using Output = std::vector; + using Config = PipelineConfig; + + Pipeline( + const ORTCHAR_T* pathDetector, const ORTCHAR_T* pathRecognizer, + std::span langList, bool useGPU = true, + int timeout = DEFAULT_PIPELINE_TIMEOUT_SECONDS, + const PipelineConfig& config = PipelineConfig{}); + + ~Pipeline() override = default; + + std::any process(const std::any& input) final; + + // Direct process method for internal use + Output process(Input input); + + void initializeBackend(); + bool isLoaded() const; + + void reset(); - Pipeline( - const ORTCHAR_T* pathDetector, const ORTCHAR_T* pathRecognizer, - std::span langList, bool useGPU = true, - int timeout = DEFAULT_PIPELINE_TIMEOUT_SECONDS, - const PipelineConfig& config = PipelineConfig{}); + [[nodiscard]] std::string getName() const final { return "Pipeline"; } - Output process(Input input); - Output process(Input, std::function callback); + void cancel() const final { + // Pipeline doesn't support cancellation during processing + } - void initializeBackend(); - bool isLoaded(); + void setWeightsForFile( + const std::string& filename, + std::unique_ptr>&& shard) final { + // Pipeline doesn't support streaming weights + (void)filename; + (void)shard; + } - void reset(); + void waitForLoadInitialization() final { + // Pipeline loads synchronously + } - qvac_lib_inference_addon_cpp::RuntimeStats runtimeStats(); + [[nodiscard]] qvac_lib_inference_addon_cpp::RuntimeStats + runtimeStats() const final; - const PipelineConfig& config() const { return config_; } + const PipelineConfig& config() const { return config_; } - private: - PipelineConfig config_; +private: + PipelineConfig config_; - // Sequential pipeline steps (no threading) - std::unique_ptr stepDetection_; - std::unique_ptr stepBoundingBox_; - std::unique_ptr stepRecognition_; + // Sequential pipeline steps (no threading) + std::unique_ptr stepDetection_; + std::unique_ptr stepBoundingBox_; + std::unique_ptr stepRecognition_; - int timeout_; + int timeout_; - std::mutex processingTimeMtx_; - std::stack processingTime_; - std::stack detectionTime_; - std::stack recognitionTime_; - std::stack textRegionsCount_; + mutable std::mutex processingTimeMtx_; + mutable std::stack processingTime_; + mutable std::stack detectionTime_; + mutable std::stack recognitionTime_; + mutable std::stack textRegionsCount_; }; } // namespace qvac_lib_inference_addon_onnx_ocr_fasttext diff --git a/packages/qvac-lib-inference-addon-onnx-ocr-fasttext/index.js b/packages/qvac-lib-inference-addon-onnx-ocr-fasttext/index.js index b696f09f57..fe5f7f4676 100644 --- a/packages/qvac-lib-inference-addon-onnx-ocr-fasttext/index.js +++ b/packages/qvac-lib-inference-addon-onnx-ocr-fasttext/index.js @@ -12,6 +12,9 @@ const addon = require.addon.resolve('.') * ONNX client implementation for OCR model */ class ONNXOcr extends ONNXBase { + // Only one job is supported at the moment, with a single job ID + static JOB_ID = 'job' + /** * Creates an instance of ONNXBase. * @constructor @@ -91,10 +94,29 @@ class ONNXOcr extends ONNXBase { onnxOcrParams.recognizerBatchSize = this.params.recognizerBatchSize } - this.addon = this._createAddon(OcrFasttextInterface, onnxOcrParams, this._outputCallback.bind(this), console.log) + this.addon = this._createAddon(OcrFasttextInterface, onnxOcrParams, this._addonOutputCallback.bind(this), console.log) await this.addon.activate() } + _addonOutputCallback (addon, event, data, error) { + // Map C++ mangled type names to expected event names + // Check stats FIRST (before other checks, since stats event name may contain other type names) + if (typeof data === 'object' && data !== null && 'totalTime' in data) { + // Stats object received - this signals job completion + // Pass stats with JobEnded event (base class expects stats in JobEnded data) + return this._outputCallback(addon, 'JobEnded', ONNXOcr.JOB_ID, data, null) + } + + let mappedEvent = event + if (event.includes('Error')) { + mappedEvent = 'Error' + } else if (Array.isArray(data)) { + // Pipeline output is an array of InferredText + mappedEvent = 'Output' + } + return this._outputCallback(addon, mappedEvent, ONNXOcr.JOB_ID, data, error) + } + async unload () { if (this.addon) { await this.addon.destroy() @@ -104,15 +126,16 @@ class ONNXOcr extends ONNXBase { async _runInternal (input) { const imageInput = this.getImage(input.path) - const jobId = await this.addon.append({ + await this.addon.runJob({ type: 'image', input: imageInput, options: input.options }) - const response = this._createResponse(jobId) + // Only one job is supported at the moment, with a single job ID + const response = this._createResponse(ONNXOcr.JOB_ID) - this._saveJobToResponseMapping(jobId, response) + this._saveJobToResponseMapping(ONNXOcr.JOB_ID, response) return response } diff --git a/packages/qvac-lib-inference-addon-onnx-ocr-fasttext/lib/error.js b/packages/qvac-lib-inference-addon-onnx-ocr-fasttext/lib/error.js index 64a6bf1a1f..0d34ae8a37 100644 --- a/packages/qvac-lib-inference-addon-onnx-ocr-fasttext/lib/error.js +++ b/packages/qvac-lib-inference-addon-onnx-ocr-fasttext/lib/error.js @@ -20,7 +20,8 @@ const ERR_CODES = Object.freeze({ MISSING_REQUIRED_PARAMETER: 9012, UNSUPPORTED_IMAGE_FORMAT: 9013, IMAGE_DECODE_FAILED: 9014, - UNSUPPORTED_LANGUAGE: 9015 + UNSUPPORTED_LANGUAGE: 9015, + FAILED_TO_RUN_JOB: 9016 }) addCodes({ @@ -83,6 +84,10 @@ addCodes({ [ERR_CODES.UNSUPPORTED_LANGUAGE]: { name: 'UNSUPPORTED_LANGUAGE', message: (langList) => `Unsupported language: ${langList}` + }, + [ERR_CODES.FAILED_TO_RUN_JOB]: { + name: 'FAILED_TO_RUN_JOB', + message: (message) => `Failed to run job, error: ${message}` } }) diff --git a/packages/qvac-lib-inference-addon-onnx-ocr-fasttext/ocr-fasttext.js b/packages/qvac-lib-inference-addon-onnx-ocr-fasttext/ocr-fasttext.js index 6f64e26999..624fb60a14 100644 --- a/packages/qvac-lib-inference-addon-onnx-ocr-fasttext/ocr-fasttext.js +++ b/packages/qvac-lib-inference-addon-onnx-ocr-fasttext/ocr-fasttext.js @@ -47,63 +47,25 @@ class OcrFasttextInterface { } /** - * Pauses current inference process + * Cancel current inference process. */ - async pause () { - try { - binding.pause(this._handle) - } catch (err) { - throw new QvacErrorAddonOcr({ - code: ERR_CODES.FAILED_TO_PAUSE, - adds: err.message, - cause: err - }) - } - } - - /** - * Cancel an inference process by jobId, if no jobId is provided it cancel the whole queue - */ - async cancel (jobId) { + async cancel () { binding.cancel(this._handle) } /** - * Stop an inference process - */ - async stop () { - binding.stop(this._handle) - } - - /** - * Adds new input to the processing queue + * Processes new input * @param {Object} data - * @param {String} data.type - * @param {String} data.input - * @returns {Number} - job ID - */ - async append (data) { - try { - return binding.append(this._handle, data) - } catch (err) { - throw new QvacErrorAddonOcr({ - code: ERR_CODES.FAILED_TO_APPEND, - adds: err.message, - cause: err - }) - } - } - - /** - * Addon process status - * @returns {String} + * @param {String} data.type - Either 'image' for image input + * @param {Object} data.input - The input image data + * @param {Object} data.options - Optional processing options */ - async status () { + async runJob (data) { try { - return binding.status(this._handle) + return binding.runJob(this._handle, data) } catch (err) { throw new QvacErrorAddonOcr({ - code: ERR_CODES.FAILED_TO_GET_STATUS, + code: ERR_CODES.FAILED_TO_RUN_JOB, adds: err.message, cause: err }) diff --git a/packages/qvac-lib-inference-addon-onnx-ocr-fasttext/test/integration/full-ocr-suite.test.js b/packages/qvac-lib-inference-addon-onnx-ocr-fasttext/test/integration/full-ocr-suite.test.js index 0b2c3e70cf..2c254b8e55 100644 --- a/packages/qvac-lib-inference-addon-onnx-ocr-fasttext/test/integration/full-ocr-suite.test.js +++ b/packages/qvac-lib-inference-addon-onnx-ocr-fasttext/test/integration/full-ocr-suite.test.js @@ -111,7 +111,7 @@ test('Full OCR test suite', { timeout: 40 * 60 * 1000, skip: isMobile }, async f } finally { try { if (isMacCI && onnxOcr && onnxOcr.addon) { - await onnxOcr.addon.stop() + await onnxOcr.addon.cancel() await new Promise(resolve => setTimeout(resolve, 2000)) t.comment('OCR Stop complete') } diff --git a/packages/qvac-lib-inference-addon-onnx-ocr-fasttext/vcpkg.json b/packages/qvac-lib-inference-addon-onnx-ocr-fasttext/vcpkg.json index fa1c8616e9..dec535f2c1 100644 --- a/packages/qvac-lib-inference-addon-onnx-ocr-fasttext/vcpkg.json +++ b/packages/qvac-lib-inference-addon-onnx-ocr-fasttext/vcpkg.json @@ -1,8 +1,11 @@ { "name": "qvac-lib-inference-addon-onnx-ocr-fasttext", - "version": "0.1.13", + "version": "0.1.14", "dependencies": [ - "qvac-lib-inference-addon-cpp", + { + "name": "qvac-lib-inference-addon-cpp", + "version>=": "1.0.0" + }, { "name": "opencv4", "default-features": false,