V20260507-2.5.2

修复了在线更新模型后指针没更新的问题。
修复了异常崩溃时导致用户数据丢失的问题。
This commit is contained in:
2026-05-08 11:13:56 +08:00
parent 97462c8aab
commit cbf2756a16
5 changed files with 123 additions and 77 deletions
+14 -2
View File
@@ -12,11 +12,23 @@ static nlohmann::json readJsonFromPath(std::string path)
std::cerr << "Could not open the file - " << path << std::endl;
return jsonObj;
}
inputFile.seekg(0, std::ios::end);
std::streamsize fileSize = inputFile.tellg();
inputFile.seekg(0, std::ios::beg);
if(fileSize == 0)
return jsonObj;
try {
inputFile >> jsonObj;
}
catch (nlohmann::json::parse_error& e) {
std::cerr << "JSON parse error: " << e.what() << std::endl;
catch (const std::exception& e) {
std::cerr << "JSON parse error: "
<< e.what() << std::endl;
return jsonObj;
}
catch (...) {
std::cerr << "Unknown JSON error in file: "
<< path << std::endl;
return jsonObj;
}
+1 -1
View File
@@ -11,7 +11,7 @@
#include <QDir>
#pragma execution_character_set("utf-8")
const std::string softwareVersion = "20260416-2.5.1";//版本号
const std::string softwareVersion = "20260507-2.5.2";//版本号
const std::string euiJsonVersion = "1.0.6";//json标准版本
#define GigaByte 1073741824//1GB字节大小
#define globalDatabasePth "./sqlDatabase/eui_db.db" //全局数据库路径
+1 -1
View File
@@ -245,7 +245,7 @@ public:
info.callCount = 0;
info.totalTime = 0;
info.maxCostTime = 0;
info.minCostTime = 0;
info.minCostTime = 999999.0;
}
}
}
+83 -56
View File
@@ -25,6 +25,7 @@ public:
QMutexLocker locker(&vectorMutex);
return static_cast<int>(modelPtrs.size());
}
//获取最新的SEG模型
getModelPtrResult getModelPtr(const int& id) {
QMutexLocker locker(&vectorMutex);
if (id < 0 || id >= static_cast<int>(modelPtrs.size()) || id >= static_cast<int>(modelMutexs.size())) {
@@ -49,15 +50,16 @@ public:
modelPtrs[id].second = newPtr;
}
void submitTime(double time) {
QMutexLocker locker(&timeMutex);
totalTime += time;
totalTime = totalTime + time;
callCount++;
maxCostTime = std::max(maxCostTime, time);
minCostTime = std::min(minCostTime, time);
maxCostTime = std::max(maxCostTime.load(), time);
minCostTime = std::min(minCostTime.load(), time);
//每十次发送一次平均耗时到界面 每千次输出一次日志并重置数据
if (callCount % 10 == 0) {
double avgTime = callCount > 0 ? totalTime / callCount : 0.0;
emit bridge->handleAiManager_refreshTimeCostViewer(modelDiscribe, QString::number(avgTime, 'f', 2) + "ms", QString::number(maxCostTime, 'f', 2) + "ms", QString::number(minCostTime, 'f', 2) + "ms");
if (bridge != nullptr) {
emit bridge->handleAiManager_refreshTimeCostViewer(modelDiscribe, QString::number(avgTime, 'f', 2) + "ms", QString::number(maxCostTime, 'f', 2) + "ms", QString::number(minCostTime, 'f', 2) + "ms");
}
if (callCount == 1000) {
qInfo() << QString::fromStdString(path) + "近千次平均耗时" << avgTime << "ms,最高" << maxCostTime << "ms,最低" << minCostTime << "ms";
callCount = 0;
@@ -67,9 +69,9 @@ public:
}
}
}
double avgTime() { QMutexLocker locker(&timeMutex); return callCount > 0 ? totalTime / callCount : 0.0; }// 平均耗时(毫秒)
double maxTime() { QMutexLocker locker(&timeMutex); return maxCostTime; }// 最大耗时(毫秒)
double minTime() { QMutexLocker locker(&timeMutex); return minCostTime; }// 最小耗时(毫秒)
double avgTime() { return callCount > 0 ? totalTime / callCount : 0.0; }// 平均耗时(毫秒)
double maxTime() { return maxCostTime; }// 最大耗时(毫秒)
double minTime() { return minCostTime; }// 最小耗时(毫秒)
std::string path;
private:
QString modelDiscribe;//模型描述
@@ -79,9 +81,8 @@ private:
std::vector<std::pair<int, handleAiModelPtr*>> modelPtrs;
std::vector<QMutex*> modelMutexs;
QMutex timeMutex; // 保护耗时统计的互斥锁
double totalTime = 0.0, maxCostTime = 0.0, minCostTime = 99999.0;
int callCount = 0;// 提交耗时的次数
std::atomic<double> totalTime = 0.0, maxCostTime = 0.0, minCostTime = 99999.0;
std::atomic<int> callCount = 0;// 提交耗时的次数
};
class segModelWithGuard {
@@ -89,18 +90,18 @@ public:
segModelWithGuard(int idIn, std::shared_ptr<handleAiModelInfo<handdleAI::pSegmentation>> segPtrIn) {
segInfoPtr = segPtrIn;
auto modelPtrResult = segInfoPtr->getModelPtr(idIn);
segPtr = modelPtrResult.modelPtr;
modelMutex = modelPtrResult.modelMutex;
id = modelPtrResult.gpuId;
modelId = idIn;
}
~segModelWithGuard() = default;
cv::Mat Evaluate(const cv::Mat& input) {
if (!segPtr || !segInfoPtr || !modelMutex) {
qCritical() << QString::fromStdString(segInfoPtr->path) << "模型未初始化";
if (!segInfoPtr || !modelMutex) {
qCritical() << QString::fromStdString(segInfoPtr ? segInfoPtr->path : std::string()) << "模型未初始化";
return cv::Mat();
}
QMutexLocker locker(modelMutex);
auto segPtr = segInfoPtr->getModelPtr(modelId).modelPtr;
timer.restart();
cv::Mat result = segPtr->Evaluate(input);
segInfoPtr->submitTime(timer.elapsed());
@@ -108,21 +109,23 @@ public:
}
std::vector<cv::Mat> bunchEvaluate(const std::vector<cv::Mat>& input) {
std::vector<cv::Mat> result;
if (!segPtr || !segInfoPtr || !modelMutex) {
qCritical() << QString::fromStdString(segInfoPtr->path) << "模型未初始化";
if (!segInfoPtr || !modelMutex) {
qCritical() << QString::fromStdString(segInfoPtr ? segInfoPtr->path : std::string()) << "模型未初始化";
return result;
}
result.reserve(input.size());
result.reserve(input.size());
QMutexLocker locker(modelMutex);
timer.restart();
auto segPtr = segInfoPtr->getModelPtr(modelId).modelPtr;
for (const auto& img : input) {
result.push_back(segPtr->Evaluate(img));
}
segInfoPtr->submitTime(timer.elapsed());
return result;
}
private:
QElapsedTimer timer;
int id = -1;
handdleAI::pSegmentation* segPtr = nullptr;
int modelId = -1;
std::shared_ptr<handleAiModelInfo<handdleAI::pSegmentation>> segInfoPtr = nullptr;
QMutex* modelMutex = nullptr;//根据不同模型共用的锁
};
@@ -132,9 +135,8 @@ public:
clsModelWithGuard(int idIn, std::shared_ptr<handleAiModelInfo<handdleAI::pClassification>> ptrIn) {
clsInfoPtr = ptrIn;
auto modelPtrResult = clsInfoPtr->getModelPtr(idIn);
clsModelPtr = modelPtrResult.modelPtr;
modelMutex = modelPtrResult.modelMutex;
id = modelPtrResult.gpuId;
modelId = idIn;
}
~clsModelWithGuard() = default;
struct clsResult {
@@ -142,33 +144,36 @@ public:
double prob = 0.0;
};
clsResult Evaluate(const cv::Mat& input) {
if (!clsModelPtr || !clsInfoPtr || !modelMutex) {
if (!clsInfoPtr || !modelMutex) {
qCritical() << QString::fromStdString(clsInfoPtr ? clsInfoPtr->path : std::string()) << "模型未初始化";
return { -1,0.0 };
}
QMutexLocker locker(modelMutex);
timer.restart();
clsResult result{ clsModelPtr->Evaluate(input),clsModelPtr->getProbability() };
auto clsPtr = clsInfoPtr->getModelPtr(modelId).modelPtr;
clsResult result{ clsPtr->Evaluate(input),clsPtr->getProbability() };
clsInfoPtr->submitTime(timer.elapsed());
return result;
}
std::vector<clsResult> bunchEvaluate(const std::vector<cv::Mat>& input) {
std::vector<clsResult> result;
if (!clsModelPtr || !clsInfoPtr || !modelMutex) {
if (!clsInfoPtr || !modelMutex) {
qCritical() << QString::fromStdString(clsInfoPtr ? clsInfoPtr->path : std::string()) << "模型未初始化";
return result;
}
result.reserve(input.size());
QMutexLocker locker(modelMutex);
timer.restart();
auto clsPtr = clsInfoPtr->getModelPtr(modelId).modelPtr;
for (const auto& img : input) {
result.push_back({ clsModelPtr->Evaluate(img),clsModelPtr->getProbability() });
result.push_back({ clsPtr->Evaluate(img),clsPtr->getProbability() });
}
clsInfoPtr->submitTime(timer.elapsed());
return result;
}
private:
QElapsedTimer timer;
int id = -1;
handdleAI::pClassification* clsModelPtr = nullptr;
int modelId = -1;
std::shared_ptr<handleAiModelInfo<handdleAI::pClassification>> clsInfoPtr = nullptr;
QMutex* modelMutex = nullptr;
};
@@ -178,22 +183,22 @@ public:
detModelWithGuard(int idIn, std::shared_ptr<handleAiModelInfo<handdleAI::pDetection>> ptrIn) {
detInfoPtr = ptrIn;
auto modelPtrResult = detInfoPtr->getModelPtr(idIn);
detModelPtr = modelPtrResult.modelPtr;
modelMutex = modelPtrResult.modelMutex;
id = modelPtrResult.gpuId;
modelId = idIn;
}
~detModelWithGuard() = default;
// 单张推理
auto Evaluate(const cv::Mat& input) {
if (!detModelPtr || !detInfoPtr || !modelMutex) {
std::vector<handdleAI::Bbox> Evaluate(const cv::Mat& input) {
if (!detInfoPtr || !modelMutex) {
qCritical() << QString::fromStdString(detInfoPtr ? detInfoPtr->path : std::string()) << "模型未初始化";
return decltype(detModelPtr->Evaluate(input))();
return std::vector<handdleAI::Bbox>();
}
QMutexLocker locker(modelMutex);
timer.restart();
auto result = detModelPtr->Evaluate(input);
auto detPtr = detInfoPtr->getModelPtr(modelId).modelPtr;
auto result = detPtr->Evaluate(input);
detInfoPtr->submitTime(timer.elapsed());
return result;
}
@@ -203,25 +208,25 @@ public:
std::vector<std::vector<handdleAI::Bbox>> result;
if (!detModelPtr || !detInfoPtr || !modelMutex) {
if (!detInfoPtr || !modelMutex) {
qCritical() << QString::fromStdString(detInfoPtr ? detInfoPtr->path : std::string()) << "模型未初始化";
return result;
}
QMutexLocker locker(modelMutex);
timer.restart();
result.reserve(input.size());
auto detPtr = detInfoPtr->getModelPtr(modelId).modelPtr;
for (const auto& img : input) {
result.push_back(detModelPtr->Evaluate(img));
result.push_back(detPtr->Evaluate(img));
}
detInfoPtr->submitTime(timer.elapsed());
return result;
}
private:
QElapsedTimer timer;
int id = -1;
handdleAI::pDetection* detModelPtr = nullptr;
int modelId = -1;
std::shared_ptr<handleAiModelInfo<handdleAI::pDetection>> detInfoPtr = nullptr;
QMutex* modelMutex = nullptr;
};
@@ -295,8 +300,6 @@ public:
int gpuIdIn,
QString modelDiscribe) {
QMutexLocker locker(&mutex);
//如果不存在则创建新的
bool firtTime = false;
if (!segPtrs.contains(path)) {
@@ -335,6 +338,7 @@ public:
}
}
#pragma endregion
QMutexLocker locker(&mutex);
//获取详情
auto segInfo = segPtrs[path];
int modelId = segInfo->addModelPtr(
@@ -342,11 +346,11 @@ public:
gpuIdIn, modelDiscribe);
//初次时注册在线更新按钮
if (firtTime) {
if (firtTime && bridge != nullptr) {
emit bridge->modelInit_addBtn(modelDiscribe + " 模型在线更新",
"描述:" + modelDiscribe +
"\n路径:" + QString::fromStdString(path) +
+ "\nbatchSize:" + QString::number(batchSize),
"\nbatchSize:" + QString::number(batchSize),
{ "modelManager#update#seg#" + QString::fromStdString(path) + "#" + QString::number(batchSize) + "#" });
emit bridge->handleAiManager_addTimeCostViewer(modelDiscribe, { "平均耗时","最大耗时","最小耗时" });
}
@@ -362,7 +366,6 @@ public:
int gpuIdIn,
QString modelDiscribe) {
QMutexLocker locker(&mutex);
//如果不存在则创建新的
bool firtTime = false;
if (!clsPtrs.contains(path)) {
@@ -402,6 +405,7 @@ public:
}
}
#pragma endregion
QMutexLocker locker(&mutex);
//获取详情
auto clsInfo = clsPtrs[path];
int modelId = clsInfo->addModelPtr(
@@ -409,7 +413,7 @@ public:
gpuIdIn, modelDiscribe);
////初次时注册在线更新按钮
if (firtTime) {
if (firtTime && bridge != nullptr) {
emit bridge->modelInit_addBtn(modelDiscribe + " 模型在线更新",
"描述:" + modelDiscribe +
"\n路径:" + QString::fromStdString(path) +
@@ -429,7 +433,6 @@ public:
int gpuIdIn,
QString modelDiscribe) {
QMutexLocker locker(&mutex);
//如果不存在则创建新的
bool firtTime = false;
if (!detPtrs.contains(path)) {
@@ -468,6 +471,7 @@ public:
}
}
#pragma endregion
QMutexLocker locker(&mutex);
//获取详情
auto detInfo = detPtrs[path];
int modelId = detInfo->addModelPtr(
@@ -475,11 +479,11 @@ public:
gpuIdIn, modelDiscribe);
////初次时注册在线更新按钮
if (firtTime) {
if (firtTime && bridge != nullptr) {
emit bridge->modelInit_addBtn(modelDiscribe + " 模型在线更新",
"描述:" + modelDiscribe +
"\n路径:" + QString::fromStdString(path) +
+ "\nbatchSize:" + QString::number(batchSize),
"\nbatchSize:" + QString::number(batchSize),
{ "modelManager#update#det#" + QString::fromStdString(path) + "#" + QString::number(batchSize) + "#" });
emit bridge->handleAiManager_addTimeCostViewer(modelDiscribe, { "平均耗时","最大耗时","最小耗时" });
}
@@ -525,9 +529,22 @@ private:
QMutexLocker managerLocker(&mutex);
bool updated = false;
//检查模型是否存在
bool exist = segPtrs.contains(oldModelPath);
bool exist = false;
switch (type) {
case seg:
exist = segPtrs.contains(oldModelPath);
break;
case cls:
exist = clsPtrs.contains(oldModelPath);
break;
case det:
exist = detPtrs.contains(oldModelPath);
break;
}
if (!exist) {
emit bridge->modelInit_modelInitResult(false, QString::fromStdString(oldModelPath) + "模型不存在");
if (bridge != nullptr) {
emit bridge->modelInit_modelInitResult(false, QString::fromStdString(oldModelPath) + "模型不存在");
}
return;
}
@@ -556,7 +573,9 @@ private:
for (int modelId = 0; modelId < modelCount; ++modelId) {
auto oldModelPtr = segInfo->getModelPtr(modelId);
if (!oldModelPtr.modelPtr || !oldModelPtr.modelMutex) {
emit bridge->modelInit_modelInitResult(false, QString::fromStdString(oldModelPath) + "模型实例无效");
if (bridge != nullptr) {
emit bridge->modelInit_modelInitResult(false, QString::fromStdString(oldModelPath) + "模型实例无效");
}
continue;
}
handdleAI::pSegmentation* newPtr = handdleAI::CreateSegObjS((char*)oldModelPath.c_str(), batchSize, oldModelPtr.gpuId);
@@ -576,7 +595,9 @@ private:
for (int modelId = 0; modelId < modelCount; ++modelId) {
auto oldModelPtr = clsInfo->getModelPtr(modelId);
if (!oldModelPtr.modelPtr || !oldModelPtr.modelMutex) {
emit bridge->modelInit_modelInitResult(false, QString::fromStdString(oldModelPath) + "模型实例无效");
if (bridge != nullptr) {
emit bridge->modelInit_modelInitResult(false, QString::fromStdString(oldModelPath) + "模型实例无效");
}
continue;
}
handdleAI::pClassification* newPtr = handdleAI::CreateClsObjV3((char*)oldModelPath.c_str(), oldModelPtr.gpuId, batchSize);
@@ -596,7 +617,9 @@ private:
for (int modelId = 0; modelId < modelCount; ++modelId) {
auto oldModelPtr = detInfo->getModelPtr(modelId);
if (!oldModelPtr.modelPtr || !oldModelPtr.modelMutex) {
emit bridge->modelInit_modelInitResult(false, QString::fromStdString(oldModelPath) + "模型实例无效");
if (bridge != nullptr) {
emit bridge->modelInit_modelInitResult(false, QString::fromStdString(oldModelPath) + "模型实例无效");
}
continue;
}
handdleAI::pDetection* newPtr = handdleAI::CreateDetObjS((char*)oldModelPath.c_str(), batchSize, oldModelPtr.gpuId);
@@ -611,10 +634,14 @@ private:
break;
}
if (!updated) {
emit bridge->modelInit_modelInitResult(false, QString::fromStdString(oldModelPath) + "路径不存在,无法更新模型");
if (bridge != nullptr) {
emit bridge->modelInit_modelInitResult(false, QString::fromStdString(oldModelPath) + "路径不存在,无法更新模型");
}
}
else {
emit bridge->modelInit_modelInitResult(true, QString::fromStdString(oldModelPath) + "成功");
if (bridge != nullptr) {
emit bridge->modelInit_modelInitResult(true, QString::fromStdString(oldModelPath) + "成功");
}
}
}
bSignalHub* bridge;
+24 -17
View File
@@ -54,6 +54,7 @@ namespace Auth {
// 私有方法实现
void initializeDefaultUsers() {
qDebug() << "初始化默认管理账户";
// 创建默认管理员账户
users["admin"] = UserInfo("admin", hashPassword("admin123"), UserLevel::ADMIN, true);
@@ -63,18 +64,24 @@ namespace Auth {
// 创建默认ROOT账户
users["root"] = UserInfo("root", hashPassword("dseuiroot"), UserLevel::ROOT, true);
}
void checkDefaultUsers() {
bool checkDefaultUsers() {
bool result = false;
// 创建默认管理员账户
if (users.find("admin") == users.end())
if (users.find("admin") == users.end()) {
users["admin"] = UserInfo("admin", hashPassword("admin123"), UserLevel::ADMIN, true);
result = true;
}
// 创建默认访客账户
if (users.find("guest") == users.end())
if (users.find("guest") == users.end()){
users["guest"] = UserInfo("guest", hashPassword("guest123"), UserLevel::GUEST, true);
result = true;
}
// 创建默认ROOT账户
if (users.find("root") == users.end())
if (users.find("root") == users.end()) {
users["root"] = UserInfo("root", hashPassword("dseuiroot"), UserLevel::ROOT, true);
result = true;
}
return result;
}
bool loadUsersFromFile() {
@@ -167,13 +174,12 @@ namespace Auth {
saveUsersToFile();
}
else {
checkDefaultUsers();
saveUsersToFile();
if (checkDefaultUsers())
saveUsersToFile();
}
}
~UserManager() {
saveUsersToFile();
}
// 用户管理方法
@@ -327,21 +333,22 @@ namespace Auth {
return static_cast<int>(currentUserLevel) >= static_cast<int>(requiredLevel);
}
bool executeWithPermission(UserLevel requiredLevel, AuthCallback callback) {
bool executeWithPermission(UserLevel requiredLevel,
AuthCallback authSuccessCallback) {
if (hasPermission(requiredLevel)) {
callback();
authSuccessCallback();
return true;
} else {
std::string errorMessage = "Access denied. Required level: " + userLevelToString(requiredLevel) +
", Current level: " + userLevelToString(currentUserLevel);
", Current level: " + userLevelToString(currentUserLevel);
std::cerr << errorMessage << std::endl;
// 显示权限不足的弹窗
QMessageBox::warning(nullptr,
TR("权限不足"),
QString(TR("您没有足够的权限执行此操作。\n\n所需等级: %1\n当前等级: %2"))
.arg(QString::fromStdString(userLevelToString(requiredLevel)))
.arg(QString::fromStdString(userLevelToString(currentUserLevel))));
TR("权限不足"),
QString(TR("您没有足够的权限执行此操作。\n\n所需等级: %1\n当前等级: %2"))
.arg(QString::fromStdString(userLevelToString(requiredLevel)))
.arg(QString::fromStdString(userLevelToString(currentUserLevel))));
return false;
}
}