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 "aip_napi_error.h"
17
18 #include <optional>
19
20 #include "aip_log.h"
21
22 #undef LOG_TAG
23 #define LOG_TAG "AipNapiError"
24
25 namespace OHOS {
26 namespace DataIntelligence {
27 struct ErrCodeMapping {
28 int32_t nativeErrCode;
29 int32_t tsErrCode;
30 };
31
32 constexpr ErrCodeMapping NATIVE_ERR_CODE2TS_ERR_CODE[] = {
33 { NATIVE_DATABASE_INVALID_FILE_PATH, DATABASE_INVALID_FILE_PATH },
34 { NATIVE_DATABASE_ALREADY_CLOSED, DATABASE_ALREADY_CLOSED },
35 { NATIVE_DATABASE_IS_BUSY, DATABASE_IS_BUSY },
36 { NATIVE_DATABASE_WAL_FILE_EXCEEDS_LIMIT, DATABASE_WAL_FILE_EXCEEDS_LIMIT },
37 { NATIVE_DATABASE_GENERIC_ERROR, DATABASE_GENERIC_ERROR },
38 { NATIVE_DATABASE_CORRUPTED, DATABASE_CORRUPTED },
39 { NATIVE_DATABASE_PERMISSION_DENIED, DATABASE_PERMISSION_DENIED },
40 { NATIVE_DATABASE_FILE_IS_LOCKED, DATABASE_FILE_IS_LOCKED },
41 { NATIVE_DATABASE_OUT_OF_MEMORY, DATABASE_OUT_OF_MEMORY },
42 { NATIVE_DATABASE_IO_ERROR, DATABASE_IO_ERROR },
43
44 { NATIVE_E_RECALL_FAILURE, RETRIEVAL_E_RECALL_FAILURE },
45 { NATIVE_E_RERANK_FAILURE, RETRIEVAL_E_RERANK_FAILURE },
46 { NATIVE_E_INVALID_NUMBER, RETRIEVAL_E_INVALID_NUMBER },
47 { NATIVE_E_INVALID_PRIMARY_KEY, RETRIEVAL_E_INVALID_PRIMARY_KEY },
48 { NATIVE_E_UNSUPPORTED_COMPOSITE_PRIMARY_KEY, RETRIEVAL_E_UNSUPPORTED_COMPOSITE_PRIMARY_KEY },
49 { NATIVE_E_EMPTY_STRING_FIELD, RETRIEVAL_E_EMPTY_STRING_FIELD },
50 { NATIVE_E_INVALID_FILTER_INPUT, RETRIEVAL_E_INVALID_FILTER_INPUT },
51 { NATIVE_E_INVALID_RECALL_FIELD, RETRIEVAL_E_INVALID_RECALL_FIELD },
52 { NATIVE_E_HIGH_VECTOR_SIMILARITY_THRESHOLD, RETRIEVAL_E_HIGH_VECTOR_SIMILARITY_THRESHOLD },
53 { NATIVE_E_RERANK_METHOD_MISMATCH, RETRIEVAL_E_RERANK_METHOD_MISMATCH },
54 { NATIVE_E_EMPTY_PARAMETER, RETRIEVAL_E_EMPTY_PARAMETER },
55
56 { NATIVE_SUMMARY_E_INVALID_PARAMETERS, RAG_E_RAG_COMMON_ERROR },
57 { NATIVE_SUMMARY_E_INVALID_RESULT, RAG_E_RAG_COMMON_ERROR },
58 { NATIVE_SUMMARY_E_INVALID_OUTPUT, RAG_E_RAG_COMMON_ERROR },
59
60 { NATIVE_RAG_E_CONFIG_ERROR, RAG_E_RAG_PARAM_ERROR },
61 { NATIVE_RAG_E_INSTANCE_EXIST, RAG_E_RAG_ALREADY_EXISTS },
62 { NATIVE_RAG_E_INVALID_INPUT, RAG_E_RAG_PARAM_ERROR },
63 { NATIVE_RAG_E_QUERY_LENGTH_EXCEED, RAG_E_RAG_PARAM_ERROR },
64 { NATIVE_RAG_E_STREAM_BUSY, RAG_E_RAG_BUSY },
65 { NATIVE_RAG_E_INSTANCE_NOT_EXIST, RAG_E_RAG_ALREADY_CLOSED },
66 { NATIVE_RAG_E_PROMPT_ERROR, RAG_E_RAG_COMMON_ERROR },
67 { NATIVE_RAG_E_LLM_ERROR, RAG_E_LLM_REQUEST_FAILED },
68 { NATIVE_RAG_E_LLM_OCCUPIED, RAG_E_LLM_BUSY },
69 { NATIVE_RAG_E_LLM_LOAD_FAILED, RAG_E_LLM_LOAD_FAILED },
70 { NATIVE_RAG_E_LLM_TIMEOUT, RAG_E_LLM_TIMEOUT },
71 { NATIVE_RAG_E_LLM_OUTPUT_INVALID, RAG_E_LLM_OUTPUT_INVALID },
72 { NATIVE_RAG_E_RETRIEVER_TIMEOUT, RAG_E_RAG_TIMEOUT },
73
74 { NATIVE_LLM_E_PARSER_JSON_PARSE, RAG_E_RAG_COMMON_ERROR },
75 { NATIVE_LLM_E_PARSER_JSON_MEMBER, RAG_E_RAG_COMMON_ERROR },
76 { NATIVE_LLM_E_REQUEST_MALLOC, RAG_E_RAG_COMMON_ERROR },
77 { NATIVE_PROMPT_E_PLACEHOLDER_JSON_PARSE, RAG_E_RAG_COMMON_ERROR },
78 { NATIVE_PROMPT_E_CHAT_TEMP_JSON_TYPE, RAG_E_RAG_COMMON_ERROR },
79 { NATIVE_PROMPT_E_CHAT_TEMP_EMPTY_MSG, RAG_E_RAG_COMMON_ERROR },
80 { NATIVE_PROMPT_E_CHAT_TEMP_UPDATE_SYS, RAG_E_RAG_COMMON_ERROR },
81 };
82
83 struct ErrMessage {
84 int32_t code;
85 const char *message;
86 };
87
88 constexpr ErrMessage ERROR_MESSAGES [] = {
89 { PARAM_EXCEPTION, "Params check failed." },
90 { DEVICE_EXCEPTION, "The device does not support this API." },
91 { INNER_ERROR, "Inner error." },
92 { DATABASE_CORRUPTED, "Database corrupted." },
93 { DATABASE_ALREADY_CLOSED, "Already closed." },
94 { DATABASE_IS_BUSY, "The database is busy." },
95 { DATABASE_OUT_OF_MEMORY, "The database is out of memory." },
96 { DATABASE_GENERIC_ERROR, "SQLite: Generic error." },
97 { DATABASE_PERMISSION_DENIED, "SQLite: Access permission denied." },
98 { DATABASE_FILE_IS_LOCKED, "SQLite: The database file is locked." },
99 { DATABASE_IO_ERROR, "SQLite: Some kind of disk I/O error occurred." },
100 { DATABASE_WAL_FILE_EXCEEDS_LIMIT, "SQLite: The WAL file size exceeds the default limit." },
101 { DATABASE_INVALID_FILE_PATH, "Unable to open the database file." },
102 { RETRIEVAL_E_RECALL_FAILURE, "Retrieval: An error occurred during the recall phase." },
103 { RETRIEVAL_E_RERANK_FAILURE, "Retrieval: An error occurred during the re-ranking phase." },
104 { RETRIEVAL_E_INVALID_NUMBER,
105 "Retrieval: The value of the numerical parameter is outside the constrained range." },
106 { RETRIEVAL_E_INVALID_PRIMARY_KEY, "Retrieval: There are invalid primary keys." },
107 { RETRIEVAL_E_UNSUPPORTED_COMPOSITE_PRIMARY_KEY,
108 "Retrieval: A re-ranking algorithm that does not support composite primary keys was used." },
109 { RETRIEVAL_E_EMPTY_STRING_FIELD, "Retrieval: There are fields with empty strings." },
110 { RETRIEVAL_E_INVALID_FILTER_INPUT, "Retrieval: The filter input is invalid." },
111 { RETRIEVAL_E_INVALID_RECALL_FIELD, "Retrieval: There are invalid recall names in RecallCondition." },
112 { RETRIEVAL_E_HIGH_VECTOR_SIMILARITY_THRESHOLD, "Retrieval: The vector similarity threshold in VectorQuery is "
113 "higher than the tiered threshold in VectorRerankParameter." },
114 { RETRIEVAL_E_RERANK_METHOD_MISMATCH, "Retrieval: RerankMethod parameters do not match the channel type." },
115 { RETRIEVAL_E_EMPTY_PARAMETER,
116 "Retrieval: There exists a parameter value that should not be empty but is actually empty." },
117 { RAG_E_RAG_COMMON_ERROR, "Inner error." },
118 { RAG_E_LLM_TIMEOUT, "A timeout occurred when calling the LLM." },
119 { RAG_E_LLM_LOAD_FAILED, "A loading failure occurred when calling the LLM." },
120 { RAG_E_LLM_REQUEST_FAILED, "A request failure occurred when calling the LLM." },
121 { RAG_E_LLM_BUSY, "The LLM chat is busy." },
122 { RAG_E_LLM_OUTPUT_INVALID, "The output of LLM chat is invalid." },
123 { RAG_E_RAG_ALREADY_EXISTS, "The RAG session is already exists." },
124 { RAG_E_RAG_BUSY, "The RAG session is busy." },
125 { RAG_E_RAG_ALREADY_CLOSED, "Already closed." },
126 { RAG_E_RAG_USER_CANCEL, "User has canceled the stream run." },
127 { RAG_E_RAG_TIMEOUT, "A timeout occurred in the session." },
128 { RAG_E_RAG_PARAM_ERROR, "Params check failed." },
129 };
130
ConvertErrCodeNative2Ts(int32_t nativeErrCode)131 int32_t ConvertErrCodeNative2Ts(int32_t nativeErrCode)
132 {
133 int left = 0;
134 int right = sizeof(NATIVE_ERR_CODE2TS_ERR_CODE) / sizeof(NATIVE_ERR_CODE2TS_ERR_CODE[0]) - 1;
135 while (left <= right) {
136 int mid = left + (right - left) / 2;
137 if (NATIVE_ERR_CODE2TS_ERR_CODE[mid].nativeErrCode == nativeErrCode) {
138 return NATIVE_ERR_CODE2TS_ERR_CODE[mid].tsErrCode;
139 } else if (NATIVE_ERR_CODE2TS_ERR_CODE[mid].nativeErrCode < nativeErrCode) {
140 left = mid + 1;
141 } else {
142 right = mid - 1;
143 }
144 }
145 return DATABASE_GENERIC_ERROR;
146 }
147
148
CreateIntelligenceError(const napi_env & env,int32_t errorCode,const std::string & errorMsg)149 napi_value CreateIntelligenceError(const napi_env &env, int32_t errorCode, const std::string &errorMsg)
150 {
151 napi_value businessError = nullptr;
152 napi_value code = nullptr;
153 napi_value msg = nullptr;
154 NAPI_CALL(env, napi_create_int32(env, errorCode, &code));
155 NAPI_CALL(env, napi_create_string_utf8(env, errorMsg.c_str(), NAPI_AUTO_LENGTH, &msg));
156 napi_create_error(env, nullptr, msg, &businessError);
157 napi_set_named_property(env, businessError, "code", code);
158 return businessError;
159 }
160
GetIntelligenceErrMsg(int32_t errorCode)161 std::optional<std::string> GetIntelligenceErrMsg(int32_t errorCode)
162 {
163 int left = 0;
164 int right = sizeof(ERROR_MESSAGES) / sizeof(ERROR_MESSAGES[0]) - 1;
165 while (left <= right) {
166 int mid = left + (right - left) / 2;
167 if (ERROR_MESSAGES[mid].code == errorCode) {
168 return ERROR_MESSAGES[mid].message;
169 } else if (ERROR_MESSAGES[mid].code < errorCode) {
170 left = mid + 1;
171 } else {
172 right = mid - 1;
173 }
174 }
175 AIP_HILOGE("Error, messages not found");
176 return std::nullopt;
177 }
178
ThrowIntelligenceErr(const napi_env & env,int32_t errorCode,const std::string & printMsg)179 void ThrowIntelligenceErr(const napi_env &env, int32_t errorCode, const std::string &printMsg)
180 {
181 AIP_HILOGE("printMsg:%{public}s, errorCode:%{public}d", printMsg.c_str(), errorCode);
182 std::optional<std::string> msg = GetIntelligenceErrMsg(errorCode);
183 if (!msg) {
184 AIP_HILOGE("errorCode:%{public}d is invalid", errorCode);
185 return;
186 }
187 napi_value error = CreateIntelligenceError(env, errorCode, msg.value());
188 napi_throw(env, error);
189 }
190
ThrowIntelligenceErrByPromise(const napi_env & env,int32_t errorCode,const std::string & printMsg,napi_value & value)191 void ThrowIntelligenceErrByPromise(const napi_env &env, int32_t errorCode, const std::string &printMsg,
192 napi_value &value)
193 {
194 AIP_HILOGE("printMsg:%{public}s, errorCode:%{public}d", printMsg.c_str(), errorCode);
195 std::optional<std::string> msg = GetIntelligenceErrMsg(errorCode);
196 if (!msg) {
197 AIP_HILOGE("errorCode:%{public}d is invalid", errorCode);
198 return;
199 }
200 value = CreateIntelligenceError(env, errorCode, msg.value());
201 }
202 } // namespace DataIntelligence
203 } // namespae OHOS