|
|
|
@ -71,7 +71,7 @@ public class AuditExecutorServiceImpl implements AuditExecutorService { |
|
|
|
// machine:调 AI 并按策略裁决
|
|
|
|
String strictness = config.getRiskStrategy() != null ? config.getRiskStrategy() : AuditConstants.STRATEGY_NORMAL; |
|
|
|
List<MiniContentAuditTask> tasks = contentAuditTaskService.listTasksByAuditId(auditId); |
|
|
|
executeBatchAuditByType(tasks, strictness); // 进入机器审核
|
|
|
|
executeBatchAuditByType(tasks, config, strictness); |
|
|
|
List<MiniContentAuditTask> updatedTasks = contentAuditTaskService.listTasksByAuditId(auditId); |
|
|
|
return aggregateTaskResultsAndUpdateAudit(auditId, updatedTasks); |
|
|
|
} |
|
|
|
@ -94,19 +94,26 @@ public class AuditExecutorServiceImpl implements AuditExecutorService { |
|
|
|
/** |
|
|
|
* 按类型分组批量执行机审 |
|
|
|
*/ |
|
|
|
private void executeBatchAuditByType(List<MiniContentAuditTask> tasks, String strictness) { |
|
|
|
private void executeBatchAuditByType(List<MiniContentAuditTask> tasks, MiniContentAuditConfig config, String strictness) { |
|
|
|
Map<String, List<MiniContentAuditTask>> grouped = tasks.stream() |
|
|
|
.collect(Collectors.groupingBy(MiniContentAuditTask::getContentType)); |
|
|
|
|
|
|
|
String textService = config.getTextService() != null ? config.getTextService() : "ugc_moderation_byllm_pro"; |
|
|
|
String imageService = config.getImageService() != null ? config.getImageService() : "baselineCheck"; |
|
|
|
String videoService = config.getVideoService() != null ? config.getVideoService() : "videoDetection"; |
|
|
|
|
|
|
|
List<MiniContentAuditTask> textTasks = grouped.getOrDefault("text", List.of()); |
|
|
|
if (!textTasks.isEmpty()) { |
|
|
|
try { |
|
|
|
List<String> contents = textTasks.stream().map(MiniContentAuditTask::getContentValue).toList(); |
|
|
|
TextModerationPlusResponse r = aliyunContentAuditUtil.batchTextModerationPlus(contents); |
|
|
|
processBatchTextResponse(textTasks, r, strictness); |
|
|
|
} catch (Exception e) { |
|
|
|
log.error("批量文本审核失败", e); |
|
|
|
for (MiniContentAuditTask task : textTasks) { |
|
|
|
for (MiniContentAuditTask task : textTasks) { |
|
|
|
try { |
|
|
|
TextModerationPlusResponse r = aliyunContentAuditUtil.textModerationPlus(task.getContentValue(), textService); |
|
|
|
processSingleTextResponse(task, r, strictness); |
|
|
|
contentAuditTaskService.lambdaUpdate() |
|
|
|
.eq(MiniContentAuditTask::getId, task.getId()) |
|
|
|
.set(MiniContentAuditTask::getServiceName, textService) |
|
|
|
.update(); |
|
|
|
} catch (Exception e) { |
|
|
|
log.error("文本审核失败, taskId={}", task.getId(), e); |
|
|
|
contentAuditTaskService.updateTaskMachineResult( |
|
|
|
task.getId(), null, null, AuditConstants.STATUS_MANUAL_REVIEW, |
|
|
|
null, null, null, null); |
|
|
|
@ -118,10 +125,9 @@ public class AuditExecutorServiceImpl implements AuditExecutorService { |
|
|
|
if (!imageTasks.isEmpty()) { |
|
|
|
for (MiniContentAuditTask task : imageTasks) { |
|
|
|
try { |
|
|
|
ImageModerationResponse r = aliyunContentAuditUtil.imageModeration(task.getContentValue()); |
|
|
|
processSingleImageResponse(task, r, strictness); |
|
|
|
handleImageAsyncAudit(task, task.getContentValue(), imageService); |
|
|
|
} catch (Exception e) { |
|
|
|
log.error("图片审核失败, taskId={}", task.getId(), e); |
|
|
|
log.error("图片异步审核提交失败, taskId={}", task.getId(), e); |
|
|
|
contentAuditTaskService.updateTaskMachineResult( |
|
|
|
task.getId(), null, null, AuditConstants.STATUS_MANUAL_REVIEW, |
|
|
|
null, null, null, null); |
|
|
|
@ -131,61 +137,59 @@ public class AuditExecutorServiceImpl implements AuditExecutorService { |
|
|
|
|
|
|
|
List<MiniContentAuditTask> videoTasks = grouped.getOrDefault("video", List.of()); |
|
|
|
for (MiniContentAuditTask task : videoTasks) { |
|
|
|
handleVideoAudit(task, task.getContentValue()); |
|
|
|
handleVideoAudit(task, task.getContentValue(), videoService); |
|
|
|
} |
|
|
|
} |
|
|
|
|
|
|
|
/** |
|
|
|
* 批量文本审核结果处理(machine 模式:按策略裁决) |
|
|
|
* 单文本审核结果处理(machine 模式:按策略裁决) |
|
|
|
* <p> |
|
|
|
* body.data 结构:{ riskLevel: "high", result: [{ label, confidence, description }, ...] } |
|
|
|
* data.result[] 可能包含多条,取置信度最高的非 nonLabel 标签。 |
|
|
|
*/ |
|
|
|
private void processBatchTextResponse(List<MiniContentAuditTask> tasks, TextModerationPlusResponse response, String strictness) { |
|
|
|
private void processSingleTextResponse(MiniContentAuditTask task, TextModerationPlusResponse response, String strictness) { |
|
|
|
String machineResultJson = JSON.toJSONString(response); |
|
|
|
String requestId = extractRequestIdFromResponse(response); |
|
|
|
|
|
|
|
// body.data 是对象,不是数组
|
|
|
|
JSONObject dataObj = extractDataObjectFromResponse(response); |
|
|
|
if (dataObj == null) { |
|
|
|
log.info("文本审核返回data为空, requestId={}", requestId); |
|
|
|
for (MiniContentAuditTask task : tasks) { |
|
|
|
contentAuditTaskService.updateTaskMachineResult( |
|
|
|
task.getId(), machineResultJson, null, AuditConstants.STATUS_MANUAL_REVIEW, |
|
|
|
null, null, null, requestId); |
|
|
|
} |
|
|
|
log.info("文本审核返回data为空, taskId={}, requestId={}", task.getId(), requestId); |
|
|
|
contentAuditTaskService.updateTaskMachineResult( |
|
|
|
task.getId(), machineResultJson, null, AuditConstants.STATUS_MANUAL_REVIEW, |
|
|
|
null, null, null, requestId); |
|
|
|
return; |
|
|
|
} |
|
|
|
|
|
|
|
String overallRiskLevel = dataObj.getString("riskLevel"); |
|
|
|
String riskLevel = dataObj.getString("riskLevel"); |
|
|
|
JSONArray resultArray = dataObj.getJSONArray("result"); |
|
|
|
log.info("文本审核结果: requestId={}, riskLevel={}, resultSize={}", |
|
|
|
requestId, overallRiskLevel, resultArray != null ? resultArray.size() : 0); |
|
|
|
|
|
|
|
for (int i = 0; i < tasks.size(); i++) { |
|
|
|
MiniContentAuditTask task = tasks.get(i); |
|
|
|
if (resultArray != null && i < resultArray.size()) { |
|
|
|
JSONObject item = resultArray.getJSONObject(i); |
|
|
|
String label = item.getString("label"); |
|
|
|
Integer confidence = item.getInteger("confidence"); |
|
|
|
String description = item.getString("description"); |
|
|
|
log.info("文本审核[{}]: label={}, confidence={}, description={}", i, label, confidence, description); |
|
|
|
|
|
|
|
if (overallRiskLevel == null) { |
|
|
|
contentAuditTaskService.updateTaskMachineResult( |
|
|
|
task.getId(), machineResultJson, null, AuditConstants.STATUS_MANUAL_REVIEW, |
|
|
|
label, confidence, description, requestId); |
|
|
|
} else { |
|
|
|
String status = applyStrategy(overallRiskLevel, strictness); |
|
|
|
contentAuditTaskService.updateTaskMachineResult( |
|
|
|
task.getId(), machineResultJson, overallRiskLevel, status, |
|
|
|
label, confidence, description, requestId); |
|
|
|
} |
|
|
|
} |
|
|
|
JSONObject best = pickBestFromResultArray(resultArray); |
|
|
|
|
|
|
|
String label = null; |
|
|
|
Integer confidence = null; |
|
|
|
String description = null; |
|
|
|
if (best != null) { |
|
|
|
label = best.getString("label"); |
|
|
|
confidence = best.getInteger("confidence"); |
|
|
|
description = best.getString("description"); |
|
|
|
} |
|
|
|
log.info("文本审核结果: taskId={}, riskLevel={}, label={}, confidence={}, description={}", |
|
|
|
task.getId(), riskLevel, label, confidence, description); |
|
|
|
|
|
|
|
if (riskLevel == null) { |
|
|
|
contentAuditTaskService.updateTaskMachineResult( |
|
|
|
task.getId(), machineResultJson, null, AuditConstants.STATUS_MANUAL_REVIEW, |
|
|
|
label, confidence, description, requestId); |
|
|
|
} else { |
|
|
|
String status = applyStrategy(riskLevel, strictness); |
|
|
|
contentAuditTaskService.updateTaskMachineResult( |
|
|
|
task.getId(), machineResultJson, riskLevel, status, |
|
|
|
label, confidence, description, requestId); |
|
|
|
} |
|
|
|
} |
|
|
|
|
|
|
|
/** |
|
|
|
* 单张图片审核结果处理(machine 模式:按策略裁决) |
|
|
|
* <p> |
|
|
|
* data.result[] 可能包含多条,取置信度最高的非 nonLabel 标签。 |
|
|
|
*/ |
|
|
|
private void processSingleImageResponse(MiniContentAuditTask task, ImageModerationResponse response, String strictness) { |
|
|
|
String machineResultJson = JSON.toJSONString(response); |
|
|
|
@ -201,9 +205,17 @@ public class AuditExecutorServiceImpl implements AuditExecutorService { |
|
|
|
} |
|
|
|
|
|
|
|
String riskLevel = dataObj.getString("riskLevel"); |
|
|
|
String label = dataObj.getString("label"); |
|
|
|
int confidence = dataObj.getIntValue("confidence"); |
|
|
|
String description = dataObj.getString("description"); |
|
|
|
JSONArray resultArray = dataObj.getJSONArray("result"); |
|
|
|
JSONObject best = pickBestFromResultArray(resultArray); |
|
|
|
|
|
|
|
String label = null; |
|
|
|
Integer confidence = null; |
|
|
|
String description = null; |
|
|
|
if (best != null) { |
|
|
|
label = best.getString("label"); |
|
|
|
confidence = best.getInteger("confidence"); |
|
|
|
description = best.getString("description"); |
|
|
|
} |
|
|
|
log.info("图片审核结果: taskId={}, riskLevel={}, label={}, confidence={}, description={}", |
|
|
|
task.getId(), riskLevel, label, confidence, description); |
|
|
|
|
|
|
|
@ -219,19 +231,49 @@ public class AuditExecutorServiceImpl implements AuditExecutorService { |
|
|
|
} |
|
|
|
} |
|
|
|
|
|
|
|
/** |
|
|
|
* 图片审核(异步提交)。 |
|
|
|
*/ |
|
|
|
private void handleImageAsyncAudit(MiniContentAuditTask task, String imageUrl, String serviceName) { |
|
|
|
ImageAsyncModerationResponse response = aliyunContentAuditUtil.imageAsyncModeration(imageUrl, serviceName); |
|
|
|
if (response == null || response.getBody() == null) { |
|
|
|
log.warn("图片异步审核请求返回null, taskId={}", task.getId()); |
|
|
|
return; |
|
|
|
} |
|
|
|
if (response.getBody().getCode() == null || response.getBody().getCode() != 200) { |
|
|
|
log.warn("图片异步审核提交失败, taskId={}, code={}", task.getId(), response.getBody().getCode()); |
|
|
|
return; |
|
|
|
} |
|
|
|
if (response.getBody().getData() != null && response.getBody().getData().getReqId() != null) { |
|
|
|
contentAuditTaskService.lambdaUpdate() |
|
|
|
.eq(MiniContentAuditTask::getId, task.getId()) |
|
|
|
.set(MiniContentAuditTask::getTaskId, response.getBody().getData().getReqId()) |
|
|
|
.set(MiniContentAuditTask::getMachineResult, JSON.toJSONString(response)) |
|
|
|
.set(MiniContentAuditTask::getServiceName, serviceName) |
|
|
|
.set(MiniContentAuditTask::getUpdateTime, new Date()) |
|
|
|
.set(MiniContentAuditTask::getUpdateTimestamp, System.currentTimeMillis()) |
|
|
|
.update(); |
|
|
|
log.info("图片异步审核已提交, taskId={}, reqId={}, service={}", task.getId(), response.getBody().getData().getReqId(), serviceName); |
|
|
|
} |
|
|
|
} |
|
|
|
|
|
|
|
/** |
|
|
|
* 视频审核(异步)。 |
|
|
|
*/ |
|
|
|
private void handleVideoAudit(MiniContentAuditTask task, String videoUrl) { |
|
|
|
VideoModerationResponse response = aliyunContentAuditUtil.videoModeration(videoUrl); |
|
|
|
private void handleVideoAudit(MiniContentAuditTask task, String videoUrl, String serviceName) { |
|
|
|
VideoModerationResponse response = aliyunContentAuditUtil.videoModeration(videoUrl, serviceName); |
|
|
|
if (response == null) { |
|
|
|
log.warn("视频审核请求返回null, taskId={}", task.getId()); |
|
|
|
return; |
|
|
|
} |
|
|
|
String asyncTaskId = extractVideoTaskIdFromResponse(response); |
|
|
|
if (asyncTaskId != null) { |
|
|
|
task.setTaskId(asyncTaskId); |
|
|
|
contentAuditTaskService.updateById(task); |
|
|
|
contentAuditTaskService.lambdaUpdate() |
|
|
|
.eq(MiniContentAuditTask::getId, task.getId()) |
|
|
|
.set(MiniContentAuditTask::getTaskId, asyncTaskId) |
|
|
|
.set(MiniContentAuditTask::getServiceName, serviceName) |
|
|
|
.update(); |
|
|
|
log.info("视频异步审核已提交, taskId={}, aliyunTaskId={}, service={}", task.getId(), asyncTaskId, serviceName); |
|
|
|
} |
|
|
|
} |
|
|
|
|
|
|
|
@ -367,32 +409,34 @@ public class AuditExecutorServiceImpl implements AuditExecutorService { |
|
|
|
} |
|
|
|
|
|
|
|
// ================================================================
|
|
|
|
// 视频异步审核结果轮询
|
|
|
|
// 异步审核结果轮询(图片 + 视频合并查询)
|
|
|
|
// ================================================================
|
|
|
|
|
|
|
|
@Override |
|
|
|
public int pollVideoAuditResults() { |
|
|
|
List<MiniContentAuditTask> pendingTasks = contentAuditTaskService.getPendingVideoTasks(); |
|
|
|
public int pollAsyncAuditResults() { |
|
|
|
List<MiniContentAuditTask> pendingTasks = contentAuditTaskService.getPendingAsyncTasks(); |
|
|
|
if (pendingTasks.isEmpty()) { |
|
|
|
return 0; |
|
|
|
} |
|
|
|
|
|
|
|
log.info("开始轮询视频审核任务, 总数={}", pendingTasks.size()); |
|
|
|
log.info("开始轮询异步审核任务, 总数={}", pendingTasks.size()); |
|
|
|
Set<Long> affectedAuditIds = new HashSet<>(); |
|
|
|
int processedCount = 0; |
|
|
|
|
|
|
|
for (MiniContentAuditTask task : pendingTasks) { |
|
|
|
try { |
|
|
|
if (processSingleVideoTask(task)) { |
|
|
|
boolean done = "video".equals(task.getContentType()) |
|
|
|
? processSingleVideoTask(task) |
|
|
|
: processSingleImageAsyncTask(task); |
|
|
|
if (done) { |
|
|
|
affectedAuditIds.add(task.getContentAuditId()); |
|
|
|
processedCount++; |
|
|
|
} |
|
|
|
} catch (Exception e) { |
|
|
|
log.error("轮询视频任务异常, taskId={}", task.getId(), e); |
|
|
|
log.error("轮询异步任务异常, taskId={}, contentType={}", task.getId(), task.getContentType(), e); |
|
|
|
} |
|
|
|
} |
|
|
|
|
|
|
|
// machine 类型需要重新汇总
|
|
|
|
for (Long auditId : affectedAuditIds) { |
|
|
|
try { |
|
|
|
MiniContentAudit audit = contentAuditService.getById(auditId); |
|
|
|
@ -405,7 +449,7 @@ public class AuditExecutorServiceImpl implements AuditExecutorService { |
|
|
|
} |
|
|
|
} |
|
|
|
|
|
|
|
log.info("视频审核轮询完成, 已处理={}, 受影响审核={}", processedCount, affectedAuditIds.size()); |
|
|
|
log.info("异步审核轮询完成, 已处理={}, 受影响审核={}", processedCount, affectedAuditIds.size()); |
|
|
|
return processedCount; |
|
|
|
} |
|
|
|
|
|
|
|
@ -442,6 +486,39 @@ public class AuditExecutorServiceImpl implements AuditExecutorService { |
|
|
|
return false; |
|
|
|
} |
|
|
|
|
|
|
|
// FrameSummarys → AudioSummarys 优先级提取最佳标签;全为 nonLabel 则存空
|
|
|
|
String label = null; |
|
|
|
Integer confidence = null; |
|
|
|
String description = null; |
|
|
|
try { |
|
|
|
JSONObject dataJsonObj = JSON.parseObject(dataJson); |
|
|
|
JSONObject frameResult = dataJsonObj.getJSONObject("frameResult"); |
|
|
|
JSONObject audioResult = dataJsonObj.getJSONObject("audioResult"); |
|
|
|
|
|
|
|
JSONArray frameSummarys = frameResult != null ? frameResult.getJSONArray("frameSummarys") : null; |
|
|
|
JSONObject best = pickBestFromFrameSummarys(frameSummarys); |
|
|
|
if (best != null) { |
|
|
|
log.info("视频标签来自frameSummarys, taskId={}, label={}, labelSum={}", |
|
|
|
task.getId(), best.getString("label"), best.getInteger("labelSum")); |
|
|
|
} else if (audioResult != null) { |
|
|
|
JSONArray audioSummarys = audioResult.getJSONArray("audioSummarys"); |
|
|
|
best = pickBestFromFrameSummarys(audioSummarys); |
|
|
|
if (best != null) { |
|
|
|
log.info("视频标签来自audioSummarys, taskId={}, label={}, labelSum={}", |
|
|
|
task.getId(), best.getString("label"), best.getInteger("labelSum")); |
|
|
|
} |
|
|
|
} |
|
|
|
if (best == null) { |
|
|
|
log.info("视频FrameSummarys和AudioSummarys均无有效违规标签, taskId={}", task.getId()); |
|
|
|
} |
|
|
|
if (best != null) { |
|
|
|
label = best.getString("label"); |
|
|
|
description = best.getString("description"); |
|
|
|
} |
|
|
|
} catch (Exception e) { |
|
|
|
log.error("提取视频标签失败, taskId={}", task.getId(), e); |
|
|
|
} |
|
|
|
|
|
|
|
MiniContentAudit audit = contentAuditService.getById(task.getContentAuditId()); |
|
|
|
if (audit == null) { |
|
|
|
log.warn("未找到关联审核记录, taskId={}", task.getId()); |
|
|
|
@ -458,10 +535,10 @@ public class AuditExecutorServiceImpl implements AuditExecutorService { |
|
|
|
String status = applyStrategy(riskLevel, strictness); |
|
|
|
contentAuditTaskService.updateTaskMachineResult( |
|
|
|
task.getId(), dataJson, riskLevel, status, |
|
|
|
null, null, null, null); |
|
|
|
label, confidence, description, null); |
|
|
|
|
|
|
|
log.info("视频任务审核完成, taskId={}, riskLevel={}, strictness={}, status={}", |
|
|
|
task.getId(), riskLevel, strictness, status); |
|
|
|
log.info("视频任务审核完成, taskId={}, riskLevel={}, label={}, strictness={}, status={}", |
|
|
|
task.getId(), riskLevel, label, strictness, status); |
|
|
|
return true; |
|
|
|
} |
|
|
|
|
|
|
|
@ -485,6 +562,69 @@ public class AuditExecutorServiceImpl implements AuditExecutorService { |
|
|
|
} |
|
|
|
} |
|
|
|
|
|
|
|
private boolean processSingleImageAsyncTask(MiniContentAuditTask task) { |
|
|
|
String reqId = task.getTaskId(); |
|
|
|
DescribeImageModerationResultResponse response = aliyunContentAuditUtil.describeImageModerationResult(reqId); |
|
|
|
|
|
|
|
if (response == null || response.getBody() == null) { |
|
|
|
log.info("图片审核结果查询返回null, taskId={}", task.getId()); |
|
|
|
return false; |
|
|
|
} |
|
|
|
|
|
|
|
Integer code = response.getBody().getCode(); |
|
|
|
if (code == null || code != 200) { |
|
|
|
log.info("图片审核结果查询失败, taskId={}, code={}", task.getId(), code); |
|
|
|
return false; |
|
|
|
} |
|
|
|
|
|
|
|
Object data = response.getBody().getData(); |
|
|
|
if (data == null) { |
|
|
|
log.info("图片异步审核未完成(无data), taskId={}", task.getId()); |
|
|
|
return false; |
|
|
|
} |
|
|
|
|
|
|
|
String dataJson = JSON.toJSONString(data); |
|
|
|
JSONObject dataObj = JSON.parseObject(dataJson); |
|
|
|
|
|
|
|
String riskLevel = dataObj.getString("riskLevel"); |
|
|
|
if (riskLevel == null) { |
|
|
|
log.info("图片异步审核仍在处理中(无riskLevel), taskId={}", task.getId()); |
|
|
|
return false; |
|
|
|
} |
|
|
|
|
|
|
|
JSONArray resultArray = dataObj.getJSONArray("result"); |
|
|
|
JSONObject best = pickBestFromResultArray(resultArray); |
|
|
|
String label = null; |
|
|
|
Integer confidence = null; |
|
|
|
String description = null; |
|
|
|
if (best != null) { |
|
|
|
label = best.getString("label"); |
|
|
|
confidence = best.getInteger("confidence"); |
|
|
|
description = best.getString("description"); |
|
|
|
} |
|
|
|
|
|
|
|
MiniContentAudit audit = contentAuditService.getById(task.getContentAuditId()); |
|
|
|
if (audit == null) { |
|
|
|
log.warn("未找到关联审核记录, taskId={}", task.getId()); |
|
|
|
return false; |
|
|
|
} |
|
|
|
|
|
|
|
String strictness = AuditConstants.STRATEGY_NORMAL; |
|
|
|
MiniContentAuditConfig config = findAuditConfig(audit.getModuleCode()); |
|
|
|
if (config != null && config.getRiskStrategy() != null) { |
|
|
|
strictness = config.getRiskStrategy(); |
|
|
|
} |
|
|
|
|
|
|
|
String status = applyStrategy(riskLevel, strictness); |
|
|
|
contentAuditTaskService.updateTaskMachineResult( |
|
|
|
task.getId(), dataJson, riskLevel, status, |
|
|
|
label, confidence, description, null); |
|
|
|
|
|
|
|
log.info("图片异步任务审核完成, taskId={}, reqId={}, riskLevel={}, label={}, strictness={}, status={}", |
|
|
|
task.getId(), reqId, riskLevel, label, strictness, status); |
|
|
|
return true; |
|
|
|
} |
|
|
|
|
|
|
|
/** |
|
|
|
* 查找审核配置。 |
|
|
|
*/ |
|
|
|
@ -503,4 +643,63 @@ public class AuditExecutorServiceImpl implements AuditExecutorService { |
|
|
|
Boolean auditEnable = config.getAuditEnable(); |
|
|
|
return Boolean.TRUE.equals(auditEnable); |
|
|
|
} |
|
|
|
|
|
|
|
// ================================================================
|
|
|
|
// 公共提取工具方法
|
|
|
|
// ================================================================
|
|
|
|
|
|
|
|
/** |
|
|
|
* 从 result 数组中取置信度最高的非 nonLabel 标签。 |
|
|
|
* 全部为 nonLabel 时兜底取第一条。 |
|
|
|
* |
|
|
|
* @param resultArray data.result[],元素含 label / confidence / description |
|
|
|
* @return 最佳标签项,或 null |
|
|
|
*/ |
|
|
|
static JSONObject pickBestFromResultArray(JSONArray resultArray) { |
|
|
|
if (resultArray == null || resultArray.isEmpty()) return null; |
|
|
|
JSONObject best = null; |
|
|
|
double bestConf = -1; |
|
|
|
JSONObject fallback = null; |
|
|
|
for (int i = 0; i < resultArray.size(); i++) { |
|
|
|
JSONObject item = resultArray.getJSONObject(i); |
|
|
|
String label = item.getString("label"); |
|
|
|
if (label == null || label.isEmpty()) continue; |
|
|
|
if (fallback == null) fallback = item; |
|
|
|
if ("nonLabel".equals(label)) continue; |
|
|
|
double conf = item.getDoubleValue("confidence"); |
|
|
|
if (conf > bestConf) { |
|
|
|
bestConf = conf; |
|
|
|
best = item; |
|
|
|
} |
|
|
|
} |
|
|
|
if (best != null) return best; |
|
|
|
return fallback; |
|
|
|
} |
|
|
|
|
|
|
|
/** |
|
|
|
* 从视频 FrameSummarys / AudioSummarys 中取 LabelSum 最大的非 nonLabel 标签。 |
|
|
|
* 全部为 nonLabel 或空 Label 时返回 null。 |
|
|
|
* |
|
|
|
* @param summarys FrameSummarys[] 或 AudioSummarys[],元素含 Label / Description / LabelSum |
|
|
|
* @return 最佳标签项,或 null |
|
|
|
*/ |
|
|
|
static JSONObject pickBestFromFrameSummarys(JSONArray summarys) { |
|
|
|
if (summarys == null || summarys.isEmpty()) return null; |
|
|
|
JSONObject best = null; |
|
|
|
int bestSum = -1; |
|
|
|
JSONObject fallback = null; |
|
|
|
for (int i = 0; i < summarys.size(); i++) { |
|
|
|
JSONObject item = summarys.getJSONObject(i); |
|
|
|
String label = item.getString("label"); |
|
|
|
if (label == null) continue; |
|
|
|
if (fallback == null) fallback = item; |
|
|
|
if ("nonLabel".equals(label) || label.isEmpty()) continue; |
|
|
|
int sum = item.getIntValue("labelSum"); |
|
|
|
if (sum > bestSum) { |
|
|
|
bestSum = sum; |
|
|
|
best = item; |
|
|
|
} |
|
|
|
} |
|
|
|
return best != null ? best : fallback; |
|
|
|
} |
|
|
|
} |
|
|
|
|