Support unicode to get users/user APIs
This commit is contained in:
@@ -1814,10 +1814,12 @@ namespace ANSCENTER {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// No faces is a valid state (user just created or faces already removed)
|
||||||
if (faceIds.empty()) {
|
if (faceIds.empty()) {
|
||||||
LogThreadSafe("ANSFacialRecognition::DeleteFacesByUser",
|
LogThreadSafe("ANSFacialRecognition::DeleteFacesByUser",
|
||||||
"No faces found for user ID " + std::to_string(userId));
|
"No faces found for user ID " + std::to_string(userId) + " — skipping",
|
||||||
return 0;
|
LogLevel::Debug);
|
||||||
|
return 1;
|
||||||
}
|
}
|
||||||
|
|
||||||
// Delete each face from database (lock per deletion)
|
// Delete each face from database (lock per deletion)
|
||||||
|
|||||||
@@ -5,6 +5,7 @@
|
|||||||
#include <opencv2/dnn/dnn.hpp>
|
#include <opencv2/dnn/dnn.hpp>
|
||||||
#include <opencv2/highgui.hpp>
|
#include <opencv2/highgui.hpp>
|
||||||
#include <utils/ocv_common.hpp>
|
#include <utils/ocv_common.hpp>
|
||||||
|
#include <json.hpp>
|
||||||
namespace ANSCENTER {
|
namespace ANSCENTER {
|
||||||
constexpr size_t ndetections = 200;
|
constexpr size_t ndetections = 200;
|
||||||
template <typename T> T GetData(const boost::property_tree::ptree& pt, const std::string& key)
|
template <typename T> T GetData(const boost::property_tree::ptree& pt, const std::string& key)
|
||||||
@@ -684,46 +685,77 @@ namespace ANSCENTER {
|
|||||||
return faceResult;
|
return faceResult;
|
||||||
}
|
}
|
||||||
|
|
||||||
std::string ANSFRHelper::UserRecordToJsonString(const UserRecord userRecord) {
|
// Encode non-ASCII UTF-8 characters as double-escaped Unicode (\uXXXX) for JSON transport.
|
||||||
boost::property_tree::ptree root;
|
// Surrogate pairs are used for codepoints above U+FFFF.
|
||||||
boost::property_tree::ptree faceIds;
|
static std::string DoubleEscapeUnicode(const std::string& utf8Str) {
|
||||||
for (int i = 0; i < userRecord.FaceIds.size(); i++) {
|
bool hasNonAscii = false;
|
||||||
boost::property_tree::ptree faceIdNode;
|
for (unsigned char c : utf8Str) {
|
||||||
faceIdNode.put("", userRecord.FaceIds[i]);
|
if (c >= 0x80) { hasNonAscii = true; break; }
|
||||||
faceIds.push_back(std::make_pair("", faceIdNode));
|
|
||||||
}
|
}
|
||||||
root.put("user_id", userRecord.UserId);
|
if (!hasNonAscii) return utf8Str;
|
||||||
root.put("user_code", userRecord.UserCode);
|
std::string result;
|
||||||
root.put("user_username", userRecord.UserName);
|
result.reserve(utf8Str.size() * 2);
|
||||||
root.add_child("face_ids", faceIds);
|
size_t i = 0;
|
||||||
std::ostringstream stream;
|
while (i < utf8Str.size()) {
|
||||||
boost::property_tree::write_json(stream, root,false);
|
unsigned char c = static_cast<unsigned char>(utf8Str[i]);
|
||||||
std::string userRecordResult = stream.str();
|
if (c < 0x80) { result += utf8Str[i++]; continue; }
|
||||||
return userRecordResult;
|
uint32_t cp = 0;
|
||||||
|
if ((c & 0xE0) == 0xC0 && i + 1 < utf8Str.size()) {
|
||||||
|
cp = ((c & 0x1F) << 6) | (static_cast<unsigned char>(utf8Str[i + 1]) & 0x3F); i += 2;
|
||||||
|
} else if ((c & 0xF0) == 0xE0 && i + 2 < utf8Str.size()) {
|
||||||
|
cp = ((c & 0x0F) << 12) | ((static_cast<unsigned char>(utf8Str[i + 1]) & 0x3F) << 6) | (static_cast<unsigned char>(utf8Str[i + 2]) & 0x3F); i += 3;
|
||||||
|
} else if ((c & 0xF8) == 0xF0 && i + 3 < utf8Str.size()) {
|
||||||
|
cp = ((c & 0x07) << 18) | ((static_cast<unsigned char>(utf8Str[i + 1]) & 0x3F) << 12) | ((static_cast<unsigned char>(utf8Str[i + 2]) & 0x3F) << 6) | (static_cast<unsigned char>(utf8Str[i + 3]) & 0x3F); i += 4;
|
||||||
|
} else { i++; continue; }
|
||||||
|
if (cp <= 0xFFFF) { char buf[8]; snprintf(buf, sizeof(buf), "\\u%04x", cp); result += buf; }
|
||||||
|
else { cp -= 0x10000; char buf[16]; snprintf(buf, sizeof(buf), "\\u%04x\\u%04x", 0xD800 + (uint16_t)(cp >> 10), 0xDC00 + (uint16_t)(cp & 0x3FF)); result += buf; }
|
||||||
|
}
|
||||||
|
return result;
|
||||||
}
|
}
|
||||||
std::string ANSFRHelper::UserRecordsToJsonString(const std::vector<UserRecord> userRecords) {
|
|
||||||
boost::property_tree::ptree root;
|
// Using nlohmann/json (consistent with FaceObjectsToJsonString)
|
||||||
boost::property_tree::ptree userRecordNodes;
|
std::string ANSFRHelper::UserRecordToJsonString(const UserRecord userRecord) {
|
||||||
for (int i=0; i < userRecords.size(); i++) {
|
try {
|
||||||
boost::property_tree::ptree userRecordNode;
|
nlohmann::json faceIdArray = nlohmann::json::array();
|
||||||
boost::property_tree::ptree faceIds;
|
for (const auto& faceId : userRecord.FaceIds) {
|
||||||
UserRecord userRecord = userRecords[i];
|
faceIdArray.push_back(faceId);
|
||||||
for (int j = 0; j < userRecord.FaceIds.size(); j++) {
|
|
||||||
boost::property_tree::ptree faceIdNode;
|
|
||||||
faceIdNode.put("", userRecord.FaceIds[j]);
|
|
||||||
faceIds.push_back(std::make_pair("", faceIdNode));
|
|
||||||
}
|
}
|
||||||
userRecordNode.put("user_id", userRecord.UserId);
|
nlohmann::json root = {
|
||||||
userRecordNode.put("user_code", userRecord.UserCode);
|
{"user_id", std::to_string(userRecord.UserId)},
|
||||||
userRecordNode.put("user_username", userRecord.UserName);
|
{"user_code", userRecord.UserCode},
|
||||||
userRecordNode.add_child("face_ids", faceIds);
|
{"user_username", DoubleEscapeUnicode(userRecord.UserName)},
|
||||||
userRecordNodes.push_back(std::make_pair("", userRecordNode));
|
{"face_ids", faceIdArray}
|
||||||
|
};
|
||||||
|
return root.dump();
|
||||||
|
}
|
||||||
|
catch (const std::exception&) {
|
||||||
|
return R"({})";
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// Using nlohmann/json (consistent with FaceObjectsToJsonString)
|
||||||
|
std::string ANSFRHelper::UserRecordsToJsonString(const std::vector<UserRecord> userRecords) {
|
||||||
|
try {
|
||||||
|
nlohmann::json root;
|
||||||
|
auto& records = root["user_records"] = nlohmann::json::array();
|
||||||
|
|
||||||
|
for (const auto& userRecord : userRecords) {
|
||||||
|
nlohmann::json faceIdArray = nlohmann::json::array();
|
||||||
|
for (const auto& faceId : userRecord.FaceIds) {
|
||||||
|
faceIdArray.push_back(faceId);
|
||||||
|
}
|
||||||
|
records.push_back({
|
||||||
|
{"user_id", std::to_string(userRecord.UserId)},
|
||||||
|
{"user_code", userRecord.UserCode},
|
||||||
|
{"user_username", DoubleEscapeUnicode(userRecord.UserName)},
|
||||||
|
{"face_ids", faceIdArray}
|
||||||
|
});
|
||||||
|
}
|
||||||
|
return root.dump();
|
||||||
|
}
|
||||||
|
catch (const std::exception&) {
|
||||||
|
return R"({"user_records":[]})";
|
||||||
}
|
}
|
||||||
root.add_child("user_records", userRecordNodes);
|
|
||||||
std::ostringstream stream;
|
|
||||||
boost::property_tree::write_json(stream, root,false);
|
|
||||||
std::string userRecordResult = stream.str();
|
|
||||||
return userRecordResult;
|
|
||||||
}
|
}
|
||||||
std::string ANSFRHelper::FaceRecordToJsonString(const FaceRecord faceRecord) {
|
std::string ANSFRHelper::FaceRecordToJsonString(const FaceRecord faceRecord) {
|
||||||
boost::property_tree::ptree root;
|
boost::property_tree::ptree root;
|
||||||
|
|||||||
@@ -37,6 +37,7 @@ target_include_directories(ANSFR-UnitTest PRIVATE
|
|||||||
${ANSLIBS_DIR}/faiss
|
${ANSLIBS_DIR}/faiss
|
||||||
${ANSLIBS_DIR}/TensorRT/include
|
${ANSLIBS_DIR}/TensorRT/include
|
||||||
${ANSLIBS_DIR}/fastdeploy_gpu/include
|
${ANSLIBS_DIR}/fastdeploy_gpu/include
|
||||||
|
${ANSLIBS_DIR}/nlohmann
|
||||||
)
|
)
|
||||||
|
|
||||||
target_link_libraries(ANSFR-UnitTest
|
target_link_libraries(ANSFR-UnitTest
|
||||||
|
|||||||
Reference in New Issue
Block a user