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