1 /*
2 * Copyright (c) 2025 Huawei Device Co., Ltd.
3 * Licensed under the Apache License, Version 2.0 (the "License");
4 * you may not use this file except in compliance with the License.
5 * You may obtain a copy of the License at
6 *
7 * http://www.apache.org/licenses/LICENSE-2.0
8 *
9 * Unless required by applicable law or agreed to in writing, software
10 * distributed under the License is distributed on an "AS IS" BASIS,
11 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
12 * See the License for the specific language governing permissions and
13 * limitations under the License.
14 */
15
16 #include "text_embedding_napi.h"
17
18 #include <dlfcn.h>
19
20 #include "aip_log.h"
21 #include "aip_napi_error.h"
22 #include "aip_napi_utils.h"
23 #include "i_aip_core_manager_impl.h"
24
25 #undef LOG_TAG
26 #define LOG_TAG "TextEmbeddingNapi"
27
28 namespace OHOS {
29 namespace DataIntelligence {
30 namespace {
31 const int32_t ERR_OK = 0;
32 static constexpr uint8_t ARG_0 = 0;
33 static constexpr uint8_t ARG_1 = 1;
34 static constexpr uint8_t ARG_2 = 2;
35
36 static constexpr uint8_t NUM_0 = 0;
37 static constexpr uint8_t NUM_1 = 1;
38 static constexpr uint8_t BASIC_MODEL = 0;
39 static constexpr uint32_t MAX_STR_PARAM_LEN = 512;
40 static const std::string CLASS_NAME = "TextEmbedding";
41 const std::vector<std::string> EXPECTED_SPLITTEXT_ARG_TYPES = { "string", "object" };
42 const std::vector<std::string> EXPECTED_GET_TEXT_MODEL_ARG_TYPES = { "object" };
43 const std::string AIP_MANAGER_PATH = "/system/lib64/platformsdk/libaip_core.z.so";
44 } // namespace
45 AipCoreManagerHandle TextEmbeddingNapi::textAipCoreMgrHandle_{};
46 thread_local napi_ref TextEmbeddingNapi::sConstructor_ = nullptr;
47 IAipCoreManager *TextEmbeddingNapi::textAipCoreManager_ = nullptr;
48
49 struct LoadCallbackData {
50 napi_async_work asyncWork;
51 napi_deferred deferred;
52 int32_t ret;
53 };
54
55 struct ReleaseCallbackData {
56 napi_async_work asyncWork;
57 napi_deferred deferred;
58 int32_t ret;
59 };
60
61 struct TextStringCallbackData {
62 napi_async_work asyncWork;
63 napi_deferred deferred;
64 std::string strArg;
65 int32_t dataRet;
66 std::vector<float> ret;
67 };
68
69 struct TextArrayCallbackData {
70 napi_async_work asyncWork;
71 napi_deferred deferred;
72 std::vector<std::string> text;
73 int32_t dataRet;
74 std::vector<std::vector<float>> ret;
75 };
76
77
78 struct SplitTextCallbackData {
79 napi_async_work asyncWork;
80 napi_deferred deferred;
81 std::string strArg;
82 int32_t configSize;
83 double configOverlap;
84 int32_t dataRet;
85 std::vector<std::string> ret;
86 };
87
88 struct TextEmbeddingConstructorInfo {
89 std::string className;
90 napi_ref *classRef;
91 napi_callback constructor;
92 const napi_property_descriptor *property;
93 size_t propertyCount;
94 const napi_property_descriptor *staticProperty;
95 size_t staticPropertyCount;
96 };
97
TextEmbeddingNapi()98 TextEmbeddingNapi::TextEmbeddingNapi() : env_(nullptr) {}
99
~TextEmbeddingNapi()100 TextEmbeddingNapi::~TextEmbeddingNapi()
101 {
102 AIP_HILOGI("Enter");
103 AipNapiUtils::UnLoadAlgoLibrary(textAipCoreMgrHandle_);
104 delete textAipCoreManager_;
105 }
106
StartInit(napi_env env,napi_value exports,struct TextEmbeddingConstructorInfo info)107 static napi_value StartInit(napi_env env, napi_value exports, struct TextEmbeddingConstructorInfo info)
108 {
109 napi_value constructor = nullptr;
110 napi_status status = napi_define_class(env, info.className.c_str(), NAPI_AUTO_LENGTH, info.constructor, nullptr,
111 info.propertyCount, info.property, &constructor);
112 if (status != napi_ok) {
113 AIP_HILOGE("define class fail");
114 return nullptr;
115 }
116
117 status = napi_create_reference(env, constructor, NUM_1, info.classRef);
118 if (status != napi_ok) {
119 AIP_HILOGE("create reference fail");
120 return nullptr;
121 }
122
123 napi_value global = nullptr;
124 status = napi_get_global(env, &global);
125 if (status != napi_ok) {
126 AIP_HILOGE("create global fail");
127 return nullptr;
128 }
129
130 status = napi_set_named_property(env, global, info.className.c_str(), constructor);
131 if (status != napi_ok) {
132 AIP_HILOGE("Init::set global named property fail");
133 return nullptr;
134 }
135
136 status = napi_define_properties(env, exports, info.staticPropertyCount, info.staticProperty);
137 if (status != napi_ok) {
138 AIP_HILOGE("define properties fail");
139 return nullptr;
140 }
141 return exports;
142 }
143
Init(napi_env env,napi_value exports)144 napi_value TextEmbeddingNapi::Init(napi_env env, napi_value exports)
145 {
146 AIP_HILOGD("Enter");
147 if (!AipNapiUtils::LoadAlgoLibrary(AIP_MANAGER_PATH, textAipCoreMgrHandle_)) {
148 AIP_HILOGE("LoadAlgoLibrary failed");
149 }
150
151 if (textAipCoreMgrHandle_.pAipManager != nullptr) {
152 textAipCoreManager_ = AipNapiUtils::GetAlgoObj(textAipCoreMgrHandle_);
153 } else {
154 textAipCoreManager_ = new IAipCoreManagerImpl();
155 }
156
157 if (textAipCoreManager_ == nullptr) {
158 AIP_HILOGE("GetAlgoObj failed");
159 return nullptr;
160 }
161
162 napi_property_descriptor properties[] = {
163 DECLARE_NAPI_FUNCTION("loadModel", LoadModel),
164 DECLARE_NAPI_FUNCTION("releaseModel", ReleaseModel),
165 DECLARE_NAPI_FUNCTION("getEmbedding", GetEmbedding),
166 };
167
168 napi_property_descriptor static_prop[] = {
169 DECLARE_NAPI_STATIC_FUNCTION("getTextEmbeddingModel", GetTextEmbeddingModel),
170 DECLARE_NAPI_STATIC_FUNCTION("splitText", SplitText),
171 };
172
173 napi_value modelVersion;
174 napi_status status = napi_create_object(env, &modelVersion);
175 if (status != napi_ok) {
176 AIP_HILOGE("Failed create object");
177 return nullptr;
178 }
179
180 AipNapiUtils::SetInt32Property(env, modelVersion, BASIC_MODEL, "BASIC_MODEL");
181 AipNapiUtils::SetPropertyName(env, exports, "ModelVersion", modelVersion);
182
183 struct TextEmbeddingConstructorInfo info = {
184 .className = CLASS_NAME,
185 .classRef = &sConstructor_,
186 .constructor = TextConstructor,
187 .property = properties,
188 .propertyCount = sizeof(properties) / sizeof(properties[NUM_0]),
189 .staticProperty = static_prop,
190 .staticPropertyCount = sizeof(static_prop) / sizeof(static_prop[NUM_0]),
191 };
192
193 if (StartInit(env, exports, info)) {
194 return nullptr;
195 }
196 return exports;
197 }
198
TextConstructor(napi_env env,napi_callback_info info)199 napi_value TextEmbeddingNapi::TextConstructor(napi_env env, napi_callback_info info)
200 {
201 napi_value undefineValue = nullptr;
202 napi_get_undefined(env, &undefineValue);
203
204 napi_status status;
205 napi_value thisVar = nullptr;
206 status = napi_get_cb_info(env, info, nullptr, nullptr, &thisVar, nullptr);
207 if (status == napi_ok && thisVar != nullptr) {
208 std::unique_ptr<TextEmbeddingNapi> txtEmbNapi = std::make_unique<TextEmbeddingNapi>();
209 if (txtEmbNapi != nullptr) {
210 txtEmbNapi->env_ = env;
211 status = napi_wrap(env, thisVar, reinterpret_cast<void *>(txtEmbNapi.get()), TextEmbeddingNapi::Destructor,
212 nullptr, nullptr);
213 if (status == napi_ok) {
214 txtEmbNapi.release();
215 return thisVar;
216 } else {
217 AIP_HILOGE("Failure wrapping js to native napi");
218 }
219 }
220 }
221 return undefineValue;
222 }
223
Destructor(napi_env env,void * nativeObject,void * finalize)224 void TextEmbeddingNapi::Destructor(napi_env env, void *nativeObject, void *finalize)
225 {
226 AIP_HILOGD("TextEmbeddingNapi, Destructor");
227 }
228
GetTextEmbeddingModel(napi_env env,napi_callback_info info)229 napi_value TextEmbeddingNapi::GetTextEmbeddingModel(napi_env env, napi_callback_info info)
230 {
231 AIP_HILOGE("Enter");
232 size_t argc = ARG_1;
233 napi_value args[ARG_1] = { nullptr };
234 napi_value jsThis = nullptr;
235
236 napi_status status = napi_get_cb_info(env, info, &argc, args, &jsThis, nullptr);
237 if (status != napi_ok) {
238 ThrowIntelligenceErr(env, PARAM_EXCEPTION, "napi_get_cb_info failed");
239 return nullptr;
240 }
241
242 if (!AipNapiUtils::ValidateArgsType(env, args, argc, EXPECTED_GET_TEXT_MODEL_ARG_TYPES)) {
243 ThrowIntelligenceErr(env, PARAM_EXCEPTION, "ValidateArgsType failed");
244 return nullptr;
245 }
246
247 ModelConfigData textModelConfig;
248 if (!ParseModelConfig(env, args, argc, &textModelConfig)) {
249 ThrowIntelligenceErr(env, PARAM_EXCEPTION, "ParseModelConfig failed");
250 return nullptr;
251 }
252
253 napi_value promise = nullptr;
254 napi_deferred deferred = nullptr;
255 status = napi_create_promise(env, &deferred, &promise);
256 if (status != napi_ok) {
257 ThrowIntelligenceErr(env, PARAM_EXCEPTION, "create promise failed");
258 return nullptr;
259 }
260
261 auto asyncGetTextEmbeddingModelData = new AsyncGetTextEmbeddingModelData{
262 .asyncWork = nullptr,
263 .deferred = deferred,
264 .config = textModelConfig,
265 };
266
267 if (!CreateAsyncTextModelExecution(env, asyncGetTextEmbeddingModelData)) {
268 ThrowIntelligenceErr(env, PARAM_EXCEPTION, "create AsyncTextModelExecution failed");
269 delete asyncGetTextEmbeddingModelData;
270 return nullptr;
271 }
272
273 return promise;
274 }
275
ParseModelConfig(napi_env env,napi_value * args,size_t argc,ModelConfigData * textModelConfig)276 bool TextEmbeddingNapi::ParseModelConfig(napi_env env, napi_value *args, size_t argc, ModelConfigData *textModelConfig)
277 {
278 AIP_HILOGI("Enter");
279 if (textModelConfig == nullptr) {
280 AIP_HILOGE("The modelConfig is null");
281 return false;
282 }
283 if (!AipNapiUtils::CheckModelConfig(env, args[ARG_0])) {
284 AIP_HILOGE("The modelConfig is failed");
285 return false;
286 }
287
288 napi_value version;
289 napi_value isNPUAvailable;
290 napi_value cachePath;
291 napi_status status = napi_get_named_property(env, args[ARG_0], "version", &version);
292 if (status != napi_ok) {
293 AIP_HILOGE("napi get version property failed");
294 return false;
295 }
296
297 if (!AipNapiUtils::TransJsToInt32(env, version, textModelConfig->versionValue)) {
298 AIP_HILOGE("Trans version failed");
299 return false;
300 }
301
302 if (textModelConfig->versionValue != BASIC_MODEL) {
303 AIP_HILOGE("The version value is invalid");
304 return false;
305 }
306
307 status = napi_get_named_property(env, args[ARG_0], "isNpuAvailable", &isNPUAvailable);
308 if (status != napi_ok) {
309 AIP_HILOGE("napi get isNpuAvailable property failed");
310 return false;
311 }
312
313 if (!AipNapiUtils::TransJsToBool(env, isNPUAvailable, textModelConfig->isNPUAvailableValue)) {
314 AIP_HILOGE("Trans isNPUAvailable failed");
315 return false;
316 }
317
318 if (textModelConfig->isNPUAvailableValue) {
319 status = napi_get_named_property(env, args[ARG_0], "cachePath", &cachePath);
320 if (status != napi_ok) {
321 AIP_HILOGE("napi get cachePath property failed");
322 return false;
323 }
324
325 if (!AipNapiUtils::TransJsToStr(env, cachePath, textModelConfig->cachePathValue)) {
326 AIP_HILOGE("Trans cachePath failed");
327 return false;
328 }
329 } else {
330 textModelConfig->cachePathValue = "";
331 }
332 return true;
333 }
334
CreateAsyncTextModelExecution(napi_env env,AsyncGetTextEmbeddingModelData * asyncModelData)335 bool TextEmbeddingNapi::CreateAsyncTextModelExecution(napi_env env, AsyncGetTextEmbeddingModelData *asyncModelData)
336 {
337 AIP_HILOGI("Enter");
338 napi_value resourceName;
339 napi_status status = napi_create_string_utf8(env, "GetTextEmbeddingModel", NAPI_AUTO_LENGTH, &resourceName);
340 if (status != napi_ok) {
341 AIP_HILOGE(" napi_create_string_utf8 failed");
342 return false;
343 }
344
345 status = napi_create_async_work(env, nullptr, resourceName, GetTextEmbeddingModelExecutionCB,
346 GetTextEmbeddingModelCompleteCB, static_cast<void *>(asyncModelData), &asyncModelData->asyncWork);
347 if (status != napi_ok) {
348 AIP_HILOGE("napi_create_async_work failed");
349 return false;
350 }
351
352 status = napi_queue_async_work_with_qos(env, asyncModelData->asyncWork, napi_qos_default);
353 if (status != napi_ok) {
354 AIP_HILOGE("napi_queue_async_work_with_qos failed");
355 return false;
356 }
357 return true;
358 }
359
360
GetTextEmbeddingModelExecutionCB(napi_env env,void * data)361 void TextEmbeddingNapi::GetTextEmbeddingModelExecutionCB(napi_env env, void *data)
362 {
363 AIP_HILOGD("Enter");
364 AsyncGetTextEmbeddingModelData *modelData = static_cast<AsyncGetTextEmbeddingModelData *>(data);
365 if (textAipCoreManager_ == nullptr) {
366 AIP_HILOGE("pAipManager is nullptr");
367 return;
368 }
369 auto config = modelData->config;
370 int32_t result = textAipCoreManager_->InitTextModel(config);
371 modelData->ret = result;
372 AIP_HILOGD("Exit");
373 }
374
GetTextEmbeddingModelCompleteCB(napi_env env,napi_status status,void * data)375 void TextEmbeddingNapi::GetTextEmbeddingModelCompleteCB(napi_env env, napi_status status, void *data)
376 {
377 AIP_HILOGD("Enter");
378 AsyncGetTextEmbeddingModelData *modelData = static_cast<AsyncGetTextEmbeddingModelData *>(data);
379 auto ret = modelData->ret;
380 napi_value result = nullptr;
381 napi_value constructor = nullptr;
382 if (ret != ERR_OK) {
383 if (ret == DEVICE_EXCEPTION) {
384 ThrowIntelligenceErrByPromise(env, DEVICE_EXCEPTION, "GetTextEmbeddingModelCompleteCB failed", result);
385 } else {
386 ThrowIntelligenceErrByPromise(env, INNER_ERROR, "GetTextEmbeddingModelCompleteCB failed", result);
387 }
388 napi_reject_deferred(env, modelData->deferred, result);
389 } else {
390 status = napi_get_reference_value(env, sConstructor_, &constructor);
391 if (status != napi_ok) {
392 AIP_HILOGE("napi_get_reference_value failed");
393 napi_get_undefined(env, &result);
394 delete modelData;
395 return;
396 }
397
398 status = napi_new_instance(env, constructor, 0, nullptr, &result);
399 if (status != napi_ok) {
400 AIP_HILOGE("napi_new_instance failed");
401 napi_get_undefined(env, &result);
402 return;
403 }
404
405 status = napi_resolve_deferred(env, modelData->deferred, result);
406 if (status != napi_ok) {
407 AIP_HILOGE(" napi_resolve_deferred failed");
408 }
409 }
410
411 status = napi_delete_async_work(env, modelData->asyncWork);
412 if (status != napi_ok) {
413 AIP_HILOGE("napi_delete_async_work failed");
414 }
415 delete modelData;
416 }
417
418
SplitText(napi_env env,napi_callback_info info)419 napi_value TextEmbeddingNapi::SplitText(napi_env env, napi_callback_info info)
420 {
421 AIP_HILOGI("Enter");
422 size_t argc = ARG_2;
423 napi_value args[ARG_2] = { nullptr };
424 napi_value jsThis = nullptr;
425
426 napi_status status = napi_get_cb_info(env, info, &argc, args, &jsThis, nullptr);
427 if (status != napi_ok) {
428 ThrowIntelligenceErr(env, PARAM_EXCEPTION, "napi_get_cb_info failed");
429 return nullptr;
430 }
431
432 if (!AipNapiUtils::ValidateArgsType(env, args, argc, EXPECTED_SPLITTEXT_ARG_TYPES)) {
433 ThrowIntelligenceErr(env, PARAM_EXCEPTION, "ValidateArgsType failed");
434 return nullptr;
435 }
436
437 std::string strArg;
438 if (!AipNapiUtils::TransJsToStrUnlimited(env, args[ARG_0], strArg)) {
439 ThrowIntelligenceErr(env, PARAM_EXCEPTION, "TransJsToStrUnlimited failed");
440 return nullptr;
441 }
442
443 napi_value cfgSize;
444 napi_value cfgOverlap;
445 if (!GetProperties(env, args[ARG_1], cfgSize, cfgOverlap)) {
446 AIP_HILOGE("content property failed");
447 ThrowIntelligenceErr(env, PARAM_EXCEPTION, "content property failed");
448 return nullptr;
449 }
450 int32_t configSize;
451 double configOverlap;
452 AipNapiUtils::TransJsToInt32(env, cfgSize, configSize);
453 AipNapiUtils::TransJsToDouble(env, cfgOverlap, configOverlap);
454 AIP_HILOGD("string strArg: %{public}d", configSize);
455 AIP_HILOGD("string strArg: %{public}f", configOverlap);
456 if (configSize <= NUM_0 || configOverlap < NUM_0 || configOverlap >= NUM_1) {
457 ThrowIntelligenceErr(env, PARAM_EXCEPTION, "The parameter value range is incorrect");
458 return nullptr;
459 }
460
461 napi_value promise = nullptr;
462 napi_deferred deferred = nullptr;
463 status = napi_create_promise(env, &deferred, &promise);
464 if (status != napi_ok) {
465 ThrowIntelligenceErr(env, PARAM_EXCEPTION, "create promise failed");
466 return nullptr;
467 }
468
469 if (!SplitTextAsyncExecution(env, deferred, strArg, configSize, configOverlap)) {
470 ThrowIntelligenceErr(env, PARAM_EXCEPTION, "create split text async execution failed");
471 return nullptr;
472 }
473 AIP_HILOGD("Exit");
474 return promise;
475 }
476
SplitTextAsyncExecution(napi_env env,napi_deferred deferred,std::string strArg,int32_t configSize,double configOverlap)477 bool TextEmbeddingNapi::SplitTextAsyncExecution(napi_env env, napi_deferred deferred, std::string strArg,
478 int32_t configSize, double configOverlap)
479 {
480 AIP_HILOGD("Enter");
481 auto splitTextCallbackData = new SplitTextCallbackData{
482 .asyncWork = nullptr,
483 .deferred = deferred,
484 .strArg = strArg,
485 .configSize = configSize,
486 .configOverlap = configOverlap,
487 };
488
489 napi_value resourceName;
490 napi_status status = napi_create_string_utf8(env, "SplitText", NAPI_AUTO_LENGTH, &resourceName);
491 if (status != napi_ok) {
492 AIP_HILOGE("napi_create_string_utf8 failed");
493 delete splitTextCallbackData;
494 return false;
495 }
496
497 status = napi_create_async_work(env, nullptr, resourceName, SplitTextExecuteCB, SplitTextCompleteCB,
498 static_cast<void *>(splitTextCallbackData), &splitTextCallbackData->asyncWork);
499 if (status != napi_ok) {
500 AIP_HILOGE("napi_create_async_work failed");
501 delete splitTextCallbackData;
502 return false;
503 }
504
505 status = napi_queue_async_work_with_qos(env, splitTextCallbackData->asyncWork, napi_qos_default);
506 if (status != napi_ok) {
507 AIP_HILOGE("napi_queue_async_work_with_qos failed");
508 napi_delete_async_work(env, splitTextCallbackData->asyncWork);
509 delete splitTextCallbackData;
510 return false;
511 }
512 return true;
513 }
514
SplitTextExecuteCB(napi_env env,void * data)515 void TextEmbeddingNapi::SplitTextExecuteCB(napi_env env, void *data)
516 {
517 AIP_HILOGD("Enter");
518 SplitTextCallbackData *splitTextCallbackData = static_cast<SplitTextCallbackData *>(data);
519 std::string strArg = splitTextCallbackData->strArg;
520 int32_t configSize = splitTextCallbackData->configSize;
521 double configOverlap = splitTextCallbackData->configOverlap;
522 std::vector<std::string> result;
523 int32_t ret = textAipCoreManager_->SplitText(strArg, configSize, static_cast<float>(configOverlap), result);
524 if (ret != ERR_OK) {
525 AIP_HILOGE("SplitText failed");
526 result = {};
527 }
528 splitTextCallbackData->ret = result;
529 splitTextCallbackData->dataRet = ret;
530 AIP_HILOGD("Exit");
531 }
SplitTextCompleteCB(napi_env env,napi_status status,void * data)532 void TextEmbeddingNapi::SplitTextCompleteCB(napi_env env, napi_status status, void *data)
533 {
534 AIP_HILOGD("Enter");
535 SplitTextCallbackData *splitTextCallbackData = static_cast<SplitTextCallbackData *>(data);
536 napi_value value = nullptr;
537 std::vector<std::string> ret = splitTextCallbackData->ret;
538 int32_t dataRet = splitTextCallbackData->dataRet;
539 if (dataRet != ERR_OK) {
540 if (dataRet == DEVICE_EXCEPTION) {
541 ThrowIntelligenceErrByPromise(env, DEVICE_EXCEPTION, "SplitTextCompleteCB failed", value);
542 } else {
543 ThrowIntelligenceErrByPromise(env, INNER_ERROR, "SplitTextCompleteCB failed", value);
544 }
545 napi_reject_deferred(env, splitTextCallbackData->deferred, value);
546 } else {
547 status = napi_create_array(env, &value);
548 if (status != napi_ok) {
549 AIP_HILOGE("napi_create_array failed");
550 } else {
551 for (size_t i = 0; i < ret.size(); i++) {
552 napi_value jsStr = nullptr;
553 napi_create_string_utf8(env, ret[i].c_str(), NAPI_AUTO_LENGTH, &jsStr);
554 napi_set_element(env, value, i, jsStr);
555 }
556 status = napi_resolve_deferred(env, splitTextCallbackData->deferred, value);
557 if (status != napi_ok) {
558 AIP_HILOGE("napi_resolve_deferred failed");
559 }
560 }
561 }
562
563 status = napi_delete_async_work(env, splitTextCallbackData->asyncWork);
564 if (status != napi_ok) {
565 AIP_HILOGE("napi_delete_async_work failed");
566 }
567 delete splitTextCallbackData;
568 }
569
570
GetProperties(napi_env env,napi_value args,napi_value & cfgSize,napi_value & cfgOverlap)571 bool TextEmbeddingNapi::GetProperties(napi_env env, napi_value args, napi_value &cfgSize, napi_value &cfgOverlap)
572 {
573 napi_status status = napi_get_named_property(env, args, "size", &cfgSize);
574 if (status != napi_ok) {
575 AIP_HILOGE("napi get size property failed");
576 return false;
577 }
578
579 status = napi_get_named_property(env, args, "overlapRatio", &cfgOverlap);
580 if (status != napi_ok) {
581 AIP_HILOGE("napi get overlapRatio property failed");
582 return false;
583 }
584 return true;
585 }
586
GetEmbedding(napi_env env,napi_callback_info info)587 napi_value TextEmbeddingNapi::GetEmbedding(napi_env env, napi_callback_info info)
588 {
589 AIP_HILOGE("Enter");
590 size_t argc = ARG_1;
591 napi_value args[ARG_1] = { nullptr };
592 napi_value jsThis = nullptr;
593
594 napi_status status = napi_get_cb_info(env, info, &argc, args, &jsThis, nullptr);
595 if (status != napi_ok) {
596 ThrowIntelligenceErr(env, INNER_ERROR, "napi_get_cb_info failed");
597 return nullptr;
598 }
599
600 if (argc != ARG_1) {
601 AIP_HILOGE("param size error");
602 ThrowIntelligenceErr(env, PARAM_EXCEPTION, "param size error");
603 return nullptr;
604 }
605
606 napi_valuetype valueType = napi_undefined;
607 status = napi_typeof(env, args[ARG_0], &valueType);
608 napi_value promise = nullptr;
609 napi_deferred deferred = nullptr;
610 status = napi_create_promise(env, &deferred, &promise);
611 if (status != napi_ok) {
612 ThrowIntelligenceErr(env, INNER_ERROR, "napi_get_cb_info failed");
613 return nullptr;
614 }
615 if (valueType == napi_string) {
616 StringType(env, args[ARG_0], promise, deferred);
617 }
618 if (valueType == napi_object) {
619 ArrayType(env, args[ARG_0], promise, deferred);
620 }
621
622 return promise;
623 }
624
StringType(napi_env env,napi_value args,napi_value promise,napi_deferred deferred)625 napi_value TextEmbeddingNapi::StringType(napi_env env, napi_value args, napi_value promise, napi_deferred deferred)
626 {
627 std::string strArg;
628 if (!AipNapiUtils::TransJsToStr(env, args, strArg)) {
629 ThrowIntelligenceErr(env, PARAM_EXCEPTION, "TransJsToStr failed");
630 return nullptr;
631 }
632
633 AIP_HILOGI("string Arg: %{public}s", strArg.c_str());
634 if (!GetEmbeddingStringAsyncExecution(env, deferred, strArg)) {
635 ThrowIntelligenceErr(env, INNER_ERROR, "GetEmbeddingStringAsyncExecution failed");
636 return nullptr;
637 }
638 AIP_HILOGD("Exit");
639 return promise;
640 }
641
GetEmbeddingStringAsyncExecution(napi_env env,napi_deferred deferred,std::string strArg)642 bool TextEmbeddingNapi::GetEmbeddingStringAsyncExecution(napi_env env, napi_deferred deferred, std::string strArg)
643 {
644 AIP_HILOGD("Enter");
645 auto textStringCallbackData = new TextStringCallbackData{
646 .asyncWork = nullptr,
647 .deferred = deferred,
648 .strArg = strArg,
649 };
650
651 napi_value resourceName;
652 napi_status status = napi_create_string_utf8(env, "textStringEmbedding", NAPI_AUTO_LENGTH, &resourceName);
653 if (status != napi_ok) {
654 AIP_HILOGE("napi_create_string_utf8 failed");
655 delete textStringCallbackData;
656 return false;
657 }
658
659 status = napi_create_async_work(env, nullptr, resourceName, GetEmbeddingStringExecuteCB,
660 GetEmbeddingStringCompleteCB, static_cast<void *>(textStringCallbackData), &textStringCallbackData->asyncWork);
661 if (status != napi_ok) {
662 AIP_HILOGE("napi_create_async_work failed");
663 delete textStringCallbackData;
664 return false;
665 }
666
667 status = napi_queue_async_work_with_qos(env, textStringCallbackData->asyncWork, napi_qos_default);
668 if (status != napi_ok) {
669 AIP_HILOGE("napi_queue_async_work_with_qos failed");
670 napi_delete_async_work(env, textStringCallbackData->asyncWork);
671 delete textStringCallbackData;
672 return false;
673 }
674 return true;
675 }
676
GetEmbeddingStringExecuteCB(napi_env env,void * data)677 void TextEmbeddingNapi::GetEmbeddingStringExecuteCB(napi_env env, void *data)
678 {
679 AIP_HILOGD("Enter");
680 TextStringCallbackData *textStringCallbackData = static_cast<TextStringCallbackData *>(data);
681 std::string strArg = textStringCallbackData->strArg;
682 std::vector<float> result;
683 int32_t ret = textAipCoreManager_->GetTextEmbedding(strArg, result);
684 textStringCallbackData->ret = result;
685 textStringCallbackData->dataRet = ret;
686 AIP_HILOGD("Exit");
687 }
688
GetEmbeddingStringCompleteCB(napi_env env,napi_status status,void * data)689 void TextEmbeddingNapi::GetEmbeddingStringCompleteCB(napi_env env, napi_status status, void *data)
690 {
691 AIP_HILOGD("Enter");
692 TextStringCallbackData *textStringCallbackData = static_cast<TextStringCallbackData *>(data);
693 napi_value value;
694 auto ret = textStringCallbackData->ret;
695 auto dataRet = textStringCallbackData->dataRet;
696 if (dataRet != ERR_OK) {
697 if (dataRet == DEVICE_EXCEPTION) {
698 ThrowIntelligenceErrByPromise(env, DEVICE_EXCEPTION, "GetEmbeddingStringCompleteCB failed", value);
699 } else {
700 ThrowIntelligenceErrByPromise(env, INNER_ERROR, "GetEmbeddingStringCompleteCB failed", value);
701 }
702 napi_reject_deferred(env, textStringCallbackData->deferred, value);
703 } else {
704 status = napi_create_array(env, &value);
705 if (status != napi_ok) {
706 AIP_HILOGE("napi_create_array failed");
707 } else {
708 for (size_t i = 0; i < ret.size(); i++) {
709 napi_value jsDouble = nullptr;
710 AipNapiUtils::CreateDoubleData(env, static_cast<double>(ret[i]), &jsDouble);
711 napi_set_element(env, value, i, jsDouble);
712 }
713 status = napi_resolve_deferred(env, textStringCallbackData->deferred, value);
714 if (status != napi_ok) {
715 AIP_HILOGE(" napi_resolve_deferred failed");
716 }
717 }
718 }
719
720 status = napi_delete_async_work(env, textStringCallbackData->asyncWork);
721 if (status != napi_ok) {
722 AIP_HILOGE("napi_delete_async_work failed");
723 }
724 delete textStringCallbackData;
725 }
726
ValidateAndDealArrayArgs(napi_env env,napi_value args,std::vector<std::string> & strArr)727 bool TextEmbeddingNapi::ValidateAndDealArrayArgs(napi_env env, napi_value args, std::vector<std::string> &strArr)
728 {
729 AIP_HILOGD("Enter");
730 bool isArray = false;
731 napi_status status = napi_is_array(env, args, &isArray);
732 if (status != napi_ok) {
733 AIP_HILOGE("check napi is array failed");
734 return false;
735 }
736
737 if (!isArray) {
738 AIP_HILOGE("argument is not array");
739 return false;
740 }
741
742 uint32_t arrayLen = 0;
743 status = napi_get_array_length(env, args, &arrayLen);
744 if (status != napi_ok) {
745 AIP_HILOGE("argument is not array");
746 return false;
747 }
748 if (arrayLen > MAX_STR_PARAM_LEN) {
749 AIP_HILOGE("argument size is too big");
750 return false;
751 }
752
753 for (uint32_t i = 0; i < arrayLen; ++i) {
754 napi_value element = nullptr;
755 status = napi_get_element(env, args, i, &element);
756 if (status != napi_ok) {
757 AIP_HILOGE("argument get array element failed");
758 return false;
759 }
760 std::string text;
761 if (!AipNapiUtils::TransJsToStr(env, element, text)) {
762 AIP_HILOGE("napi get array element error");
763 strArr.clear();
764 return false;
765 }
766 strArr.push_back(text);
767 }
768 return true;
769 }
770
ArrayType(napi_env env,napi_value args,napi_value promise,napi_deferred deferred)771 napi_value TextEmbeddingNapi::ArrayType(napi_env env, napi_value args, napi_value promise, napi_deferred deferred)
772 {
773 std::vector<std::string> text;
774 if (!ValidateAndDealArrayArgs(env, args, text)) {
775 ThrowIntelligenceErr(env, PARAM_EXCEPTION, "Validate ArrayArgs error!");
776 return nullptr;
777 }
778 if (!GetEmbeddingArrayAsyncExecution(env, deferred, text)) {
779 ThrowIntelligenceErr(env, INNER_ERROR, "GetEmbeddingArrayAsyncExecution failed!");
780 return nullptr;
781 }
782
783 AIP_HILOGD("exit");
784 return promise;
785 }
786
GetEmbeddingArrayAsyncExecution(napi_env env,napi_deferred deferred,std::vector<std::string> text)787 bool TextEmbeddingNapi::GetEmbeddingArrayAsyncExecution(napi_env env, napi_deferred deferred,
788 std::vector<std::string> text)
789 {
790 AIP_HILOGD("Enter");
791 auto textArrayCallbackData = new TextArrayCallbackData{
792 .asyncWork = nullptr,
793 .deferred = deferred,
794 .text = text,
795 };
796
797 napi_value resourceName;
798 napi_status status = napi_create_string_utf8(env, "textArrayEmbedding", NAPI_AUTO_LENGTH, &resourceName);
799 if (status != napi_ok) {
800 AIP_HILOGE("napi_create_string_utf8 failed");
801 delete textArrayCallbackData;
802 return false;
803 }
804
805 status = napi_create_async_work(env, nullptr, resourceName, GetEmbeddingArrayExecuteCB, GetEmbeddingArrayCompleteCB,
806 static_cast<void *>(textArrayCallbackData), &textArrayCallbackData->asyncWork);
807 if (status != napi_ok) {
808 AIP_HILOGE("napi_create_async_work failed");
809 delete textArrayCallbackData;
810 return false;
811 }
812
813 status = napi_queue_async_work_with_qos(env, textArrayCallbackData->asyncWork, napi_qos_default);
814 if (status != napi_ok) {
815 AIP_HILOGE("napi_queue_async_work_with_qos failed");
816 napi_delete_async_work(env, textArrayCallbackData->asyncWork);
817 delete textArrayCallbackData;
818 return false;
819 }
820 return true;
821 }
822
823
GetEmbeddingArrayExecuteCB(napi_env env,void * data)824 void TextEmbeddingNapi::GetEmbeddingArrayExecuteCB(napi_env env, void *data)
825 {
826 AIP_HILOGD("Enter");
827 TextArrayCallbackData *textArrayCallbackData = static_cast<TextArrayCallbackData *>(data);
828 auto text = textArrayCallbackData->text;
829 std::vector<std::vector<float>> result;
830 int32_t ret = textAipCoreManager_->GetTextEmbedding(text, result);
831 textArrayCallbackData->ret = result;
832 textArrayCallbackData->dataRet = ret;
833 }
834
GetEmbeddingArrayCompleteCB(napi_env env,napi_status status,void * data)835 void TextEmbeddingNapi::GetEmbeddingArrayCompleteCB(napi_env env, napi_status status, void *data)
836 {
837 AIP_HILOGD("Enter");
838 TextArrayCallbackData *textArrayCallbackData = static_cast<TextArrayCallbackData *>(data);
839 napi_value value = nullptr;
840 std::vector<std::vector<float>> ret = textArrayCallbackData->ret;
841 auto dataRet = textArrayCallbackData->dataRet;
842 if (dataRet != ERR_OK) {
843 if (dataRet == DEVICE_EXCEPTION) {
844 ThrowIntelligenceErrByPromise(env, DEVICE_EXCEPTION, "GetEmbeddingArrayCompleteCB failed", value);
845 } else {
846 ThrowIntelligenceErrByPromise(env, INNER_ERROR, "GetEmbeddingArrayCompleteCB failed", value);
847 }
848 napi_reject_deferred(env, textArrayCallbackData->deferred, value);
849 status = napi_delete_async_work(env, textArrayCallbackData->asyncWork);
850 if (status != napi_ok) {
851 AIP_HILOGE("napi_delete_async_work failed");
852 }
853 delete textArrayCallbackData;
854 return;
855 }
856
857 status = napi_create_array(env, &value);
858 if (status != napi_ok) {
859 AIP_HILOGE("napi_create_array failed");
860 } else {
861 for (size_t i = 0; i < ret.size(); ++i) {
862 napi_value res = nullptr;
863 napi_create_array(env, &res);
864 for (size_t j = 0; j < ret[i].size(); ++j) {
865 napi_value jsDouble = nullptr;
866 napi_create_double(env, static_cast<double>(ret[i][j]), &jsDouble);
867 napi_set_element(env, res, j, jsDouble);
868 }
869 napi_set_element(env, value, i, res);
870 }
871 status = napi_resolve_deferred(env, textArrayCallbackData->deferred, value);
872 if (status != napi_ok) {
873 AIP_HILOGE(" napi_resolve_deferred failed");
874 }
875 }
876
877 status = napi_delete_async_work(env, textArrayCallbackData->asyncWork);
878 if (status != napi_ok) {
879 AIP_HILOGE("napi_delete_async_work failed");
880 }
881 delete textArrayCallbackData;
882 }
883
884
LoadModel(napi_env env,napi_callback_info info)885 napi_value TextEmbeddingNapi::LoadModel(napi_env env, napi_callback_info info)
886 {
887 AIP_HILOGD("Enter");
888 size_t argc = ARG_0;
889 napi_value args[ARG_1] = { nullptr };
890 napi_value jsThis = nullptr;
891
892 napi_status status = napi_get_cb_info(env, info, &argc, args, &jsThis, nullptr);
893 if (status != napi_ok) {
894 AIP_HILOGE("napi_get_cb_info failed");
895 ThrowIntelligenceErr(env, INNER_ERROR, "napi_get_cb_info failed");
896 return nullptr;
897 }
898
899 if (argc != ARG_0) {
900 AIP_HILOGE("param size error");
901 ThrowIntelligenceErr(env, PARAM_EXCEPTION, "param size error");
902 return nullptr;
903 }
904
905 napi_value promise = nullptr;
906 napi_deferred deferred = nullptr;
907 status = napi_create_promise(env, &deferred, &promise);
908 if (status != napi_ok) {
909 ThrowIntelligenceErr(env, INNER_ERROR, "create promise failed");
910 return nullptr;
911 }
912
913 if (!LoadAsyncExecution(env, deferred)) {
914 ThrowIntelligenceErr(env, INNER_ERROR, "create promise failed");
915 return nullptr;
916 }
917 AIP_HILOGD("Exit");
918 return promise;
919 }
920
LoadAsyncExecution(napi_env env,napi_deferred deferred)921 bool TextEmbeddingNapi::LoadAsyncExecution(napi_env env, napi_deferred deferred)
922 {
923 AIP_HILOGD("Enter");
924 auto loadCallbackData = new LoadCallbackData{
925 .asyncWork = nullptr,
926 .deferred = deferred,
927 };
928
929 napi_value resourceName;
930 napi_status status = napi_create_string_utf8(env, "textLoad", NAPI_AUTO_LENGTH, &resourceName);
931 if (status != napi_ok) {
932 AIP_HILOGE("napi_create_string_utf8 failed");
933 delete loadCallbackData;
934 return false;
935 }
936
937 status = napi_create_async_work(env, nullptr, resourceName, LoadExecuteCB, LoadCompleteCB,
938 static_cast<void *>(loadCallbackData), &loadCallbackData->asyncWork);
939 if (status != napi_ok) {
940 AIP_HILOGE("napi_create_async_work failed");
941 delete loadCallbackData;
942 return false;
943 }
944
945 status = napi_queue_async_work_with_qos(env, loadCallbackData->asyncWork, napi_qos_default);
946 if (status != napi_ok) {
947 AIP_HILOGE("napi_queue_async_work_with_qos failed");
948 napi_delete_async_work(env, loadCallbackData->asyncWork);
949 delete loadCallbackData;
950 return false;
951 }
952 return true;
953 }
954
LoadExecuteCB(napi_env env,void * data)955 void TextEmbeddingNapi::LoadExecuteCB(napi_env env, void *data)
956 {
957 AIP_HILOGD("Enter");
958 LoadCallbackData *loadCallbackData = static_cast<LoadCallbackData *>(data);
959 auto ret = textAipCoreManager_->LoadTextModel();
960 loadCallbackData->ret = ret;
961 AIP_HILOGD("Exit");
962 }
963
LoadCompleteCB(napi_env env,napi_status status,void * data)964 void TextEmbeddingNapi::LoadCompleteCB(napi_env env, napi_status status, void *data)
965 {
966 AIP_HILOGD("Enter");
967 LoadCallbackData *loadCallbackData = static_cast<LoadCallbackData *>(data);
968 napi_value value = nullptr;
969 auto ret = loadCallbackData->ret;
970 if (ret != ERR_OK) {
971 if (ret == DEVICE_EXCEPTION) {
972 ThrowIntelligenceErrByPromise(env, DEVICE_EXCEPTION, "loadCallbackData failed", value);
973 } else {
974 ThrowIntelligenceErrByPromise(env, INNER_ERROR, "loadCallbackData failed", value);
975 }
976 napi_reject_deferred(env, loadCallbackData->deferred, value);
977 } else {
978 status = napi_get_undefined(env, &value);
979 if (status != napi_ok) {
980 AIP_HILOGE(" napi_get_undefined failed");
981 }
982 status = napi_resolve_deferred(env, loadCallbackData->deferred, value);
983 if (status != napi_ok) {
984 AIP_HILOGE(" napi_resolve_deferred failed");
985 }
986 }
987
988 status = napi_delete_async_work(env, loadCallbackData->asyncWork);
989 if (status != napi_ok) {
990 AIP_HILOGE("napi_delete_async_work failed");
991 }
992 delete loadCallbackData;
993 }
994
995
ReleaseModel(napi_env env,napi_callback_info info)996 napi_value TextEmbeddingNapi::ReleaseModel(napi_env env, napi_callback_info info)
997 {
998 AIP_HILOGD("Enter");
999 size_t argc = ARG_0;
1000 napi_value args[ARG_1] = { nullptr };
1001 napi_value jsThis = nullptr;
1002
1003 napi_status status = napi_get_cb_info(env, info, &argc, args, &jsThis, nullptr);
1004 if (status != napi_ok) {
1005 AIP_HILOGE("napi_get_cb_info failed");
1006 ThrowIntelligenceErr(env, INNER_ERROR, "napi_get_cb_info failed");
1007 return nullptr;
1008 }
1009
1010 if (argc != ARG_0) {
1011 ThrowIntelligenceErr(env, PARAM_EXCEPTION, "param size error");
1012 return nullptr;
1013 }
1014
1015 napi_value promise = nullptr;
1016 napi_deferred deferred = nullptr;
1017 status = napi_create_promise(env, &deferred, &promise);
1018 if (status != napi_ok) {
1019 ThrowIntelligenceErr(env, INNER_ERROR, "create promise failed");
1020 return nullptr;
1021 }
1022
1023 if (!ReleaseAsyncExecution(env, deferred)) {
1024 ThrowIntelligenceErr(env, INNER_ERROR, "releaseAsyncExecution failed");
1025 return nullptr;
1026 }
1027
1028 AIP_HILOGD("Exit");
1029 return promise;
1030 }
1031
ReleaseAsyncExecution(napi_env env,napi_deferred deferred)1032 bool TextEmbeddingNapi::ReleaseAsyncExecution(napi_env env, napi_deferred deferred)
1033 {
1034 AIP_HILOGD("Enter");
1035 auto releaseCallbackData = new ReleaseCallbackData{
1036 .asyncWork = nullptr,
1037 .deferred = deferred,
1038 };
1039
1040 napi_value resourceName;
1041 napi_status status = napi_create_string_utf8(env, "textLoad", NAPI_AUTO_LENGTH, &resourceName);
1042 if (status != napi_ok) {
1043 AIP_HILOGE("napi_create_string_utf8 failed");
1044 delete releaseCallbackData;
1045 return false;
1046 }
1047
1048 status = napi_create_async_work(env, nullptr, resourceName, ReleaseExecuteCB, ReleaseCompleteCB,
1049 static_cast<void *>(releaseCallbackData), &releaseCallbackData->asyncWork);
1050 if (status != napi_ok) {
1051 AIP_HILOGE("napi_create_async_work failed");
1052 delete releaseCallbackData;
1053 return false;
1054 }
1055
1056 status = napi_queue_async_work_with_qos(env, releaseCallbackData->asyncWork, napi_qos_default);
1057 if (status != napi_ok) {
1058 AIP_HILOGE("napi_queue_async_work_with_qos failed");
1059 napi_delete_async_work(env, releaseCallbackData->asyncWork);
1060 delete releaseCallbackData;
1061 return false;
1062 }
1063 return true;
1064 }
ReleaseExecuteCB(napi_env env,void * data)1065 void TextEmbeddingNapi::ReleaseExecuteCB(napi_env env, void *data)
1066 {
1067 AIP_HILOGD("Enter");
1068 ReleaseCallbackData *releaseCallbackData = static_cast<ReleaseCallbackData *>(data);
1069 auto ret = textAipCoreManager_->ReleaseTextModel();
1070 releaseCallbackData->ret = ret;
1071 AIP_HILOGD("Exit");
1072 }
1073
ReleaseCompleteCB(napi_env env,napi_status status,void * data)1074 void TextEmbeddingNapi::ReleaseCompleteCB(napi_env env, napi_status status, void *data)
1075 {
1076 AIP_HILOGD("Enter");
1077 ReleaseCallbackData *releaseCallbackData = static_cast<ReleaseCallbackData *>(data);
1078 napi_value value = nullptr;
1079 auto ret = releaseCallbackData->ret;
1080 if (ret != ERR_OK) {
1081 if (ret == DEVICE_EXCEPTION) {
1082 ThrowIntelligenceErrByPromise(env, DEVICE_EXCEPTION, "ReleaseCompleteCB failed", value);
1083 } else {
1084 ThrowIntelligenceErrByPromise(env, INNER_ERROR, "ReleaseCompleteCB failed", value);
1085 }
1086 napi_reject_deferred(env, releaseCallbackData->deferred, value);
1087 } else {
1088 status = napi_get_undefined(env, &value);
1089 if (status != napi_ok) {
1090 AIP_HILOGE(" napi_get_undefined failed");
1091 }
1092 status = napi_resolve_deferred(env, releaseCallbackData->deferred, value);
1093 if (status != napi_ok) {
1094 AIP_HILOGE(" napi_resolve_deferred failed");
1095 }
1096 }
1097
1098 status = napi_delete_async_work(env, releaseCallbackData->asyncWork);
1099 if (status != napi_ok) {
1100 AIP_HILOGE("napi_delete_async_work failed");
1101 }
1102 delete releaseCallbackData;
1103 }
1104 } // namespace DataIntelligence
1105 } // namespace OHOS
1106