Files
smartDriveEE/src/main/java/com/rj/service/impl/FaceDetectLogServiceImpl.java
2025-10-12 09:37:43 +08:00

439 lines
19 KiB
Java
Raw Blame History

This file contains ambiguous Unicode characters

This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.

package com.rj.service.impl;
import com.baomidou.mybatisplus.extension.service.impl.ServiceImpl;
import com.rj.entity.FaceDetectLog;
import com.rj.mapper.FaceDetectLogMapper;
import com.rj.service.IFaceDetectLogService;
import lombok.extern.slf4j.Slf4j;
import org.springframework.beans.factory.annotation.Value;
import org.springframework.http.*;
import org.springframework.stereotype.Service;
import org.springframework.web.client.RestTemplate;
import org.springframework.web.client.HttpClientErrorException;
import org.springframework.web.client.HttpServerErrorException;
import com.fasterxml.jackson.databind.ObjectMapper;
import com.fasterxml.jackson.databind.JsonNode;
import java.time.LocalDateTime;
import java.util.HashMap;
import java.util.Map;
import java.util.UUID;
/**
* 图像检测日志服务实现
*/
@Slf4j
@Service
public class FaceDetectLogServiceImpl extends ServiceImpl<FaceDetectLogMapper, FaceDetectLog> implements IFaceDetectLogService {
private static final String API_URL = "https://dashscope.aliyuncs.com/api/v1/services/aigc/image2video/face-detect";
private static final String API_URL_AA = "https://dashscope.aliyuncs.com/api/v1/services/aigc/image2video/aa-detect";
@Value("${dashscope.api.key:}")
private String apiKey;
private final RestTemplate restTemplate;
private final ObjectMapper objectMapper;
public FaceDetectLogServiceImpl() {
this.restTemplate = new RestTemplate();
this.objectMapper = new ObjectMapper();
}
@Override
public boolean saveFaceDetectLog(FaceDetectLog faceDetectLog) {
try {
return save(faceDetectLog);
} catch (Exception e) {
log.error("保存图像检测日志失败: {}", e.getMessage(), e);
return false;
}
}
/**
* 执行图像检测并保存日志
*/
public FaceDetectLog detectFaceAndSave(String imageUrl) {
return detectFaceAndSave(imageUrl, null, null, null);
}
/**
* 执行图像检测并保存日志(带扩展信息)
*/
public FaceDetectLog detectFaceAndSave(String imageUrl, String ownerName, String ownerPhone, String avatarName) {
return detectFaceAndSave(imageUrl, ownerName, ownerPhone, avatarName, null);
}
/**
* 执行图像检测并保存日志(带扩展信息和模型名)
*/
public FaceDetectLog detectFaceAndSave(String imageUrl, String ownerName, String ownerPhone, String avatarName, String model) {
if (apiKey == null || apiKey.trim().isEmpty()) {
log.error("DASHSCOPE_API_KEY未配置");
return createErrorLog(imageUrl, "DASHSCOPE_API_KEY未配置", ownerName, ownerPhone, avatarName);
}
// 创建日志记录
FaceDetectLog faceDetectLog = new FaceDetectLog();
String requestId = UUID.randomUUID().toString();
LocalDateTime requestTime = LocalDateTime.now();
faceDetectLog.setRequestId(requestId);
// 设置模型名称,如果未提供则使用默认值
String modelName = (model != null && !model.trim().isEmpty()) ? model : "liveportrait-detect";
faceDetectLog.setModel(modelName);
log.info("使用模型: {}", modelName);
faceDetectLog.setImageUrl(imageUrl);
faceDetectLog.setOwnerName(ownerName);
faceDetectLog.setOwnerPhone(ownerPhone);
faceDetectLog.setAvatarName(avatarName);
faceDetectLog.setRequestTime(requestTime);
long startTime = System.currentTimeMillis();
try {
// 创建请求体
Map<String, Object> requestBody = new HashMap<>();
requestBody.put("model", modelName);
if (modelName.equals("emo-detect-v1") || modelName.equals("emoji-detect-v1")){
Map<String, Object> ratioo = new HashMap<>();
ratioo.put("ratio", "1:1");
requestBody.put("parameters", ratioo);
}
Map<String, String> input = new HashMap<>();
input.put("image_url", imageUrl);
requestBody.put("input", input);
// 设置请求头
HttpHeaders headers = new HttpHeaders();
headers.setContentType(MediaType.APPLICATION_JSON);
headers.setBearerAuth(apiKey);
log.info("发送图像检测请求requestBody : {}, 请求参数headers: {}", requestBody , headers);
// 创建请求实体 parameters.ratio 希望检测确认的画幅,可选 "1:1"或"3:4"。默认值为"1:1"。
HttpEntity<Map<String, Object>> requestEntity = new HttpEntity<>(requestBody, headers);
ResponseEntity<String> response = null;
if ( modelName.equals("animate-anyone-detect-gen2")){
response = restTemplate.exchange(
API_URL_AA,
HttpMethod.POST,
requestEntity,
String.class
);
}else {
response = restTemplate.exchange(
API_URL,
HttpMethod.POST,
requestEntity,
String.class
);
}
// 发送请求
log.info("发送图像检测请求response {}, 图片URL: {}", response, imageUrl);
// 计算处理时间
long endTime = System.currentTimeMillis();
long processingTime = endTime - startTime;
// 更新日志记录
faceDetectLog.setResponseTime(LocalDateTime.now());
faceDetectLog.setStatusCode(response.getStatusCode().value());
faceDetectLog.setProcessingTimeMs(processingTime);
faceDetectLog.setResponseData(response.getBody());
// 处理响应
log.info("图像检测响应response: {}, 处理时间: {}ms", response.toString(), processingTime);
// 解析JSON响应
if (response.getStatusCode() == HttpStatus.OK) {
faceDetectLog.setSuccess( true);
JsonNode jsonResponse = objectMapper.readTree(response.getBody());
// 根据pass字段判断是否成功
boolean isSuccess = false;
if (jsonResponse.has("output") && jsonResponse.get("output").has("pass")) {
isSuccess = jsonResponse.get("output").get("pass").asBoolean();
faceDetectLog.setSuccess(isSuccess);
log.info("图像检测结果 - 头像 pass: {}", isSuccess);
}
if (jsonResponse.has("output") && jsonResponse.get("output").has("check_pass")) {
isSuccess = jsonResponse.get("output").get("check_pass").asBoolean();
faceDetectLog.setSuccess(isSuccess);
log.info("图像检测结果 (animate-anyone-detect-gen2 舞动人像 )- check_pass: {}", isSuccess);
}
// 检查是否有检测到图像
int faceCount = 0;
if (jsonResponse.has("output")) {
JsonNode output = jsonResponse.get("output");
// 根据pass字段判断是否检测到图像
if (output.has("pass")) {
boolean pass = output.get("pass").asBoolean();
faceDetectLog.setFaceCount(1);
log.info("图像检测结果 - pass: {}, 检测到图像数量: {}", pass, faceDetectLog.getFaceCount());
// 记录message信息
if (output.has("message")) {
String message = output.get("message").asText();
log.info("检测消息: {}", message);
}
}
// 解析图像区域坐标如果API返回中包含
if (output.has("face_bbox")) {
JsonNode faceBbox = output.get("face_bbox");
if (faceBbox.isArray()) {
String faceBboxStr = faceBbox.toString();
faceDetectLog.setFaceBbox(faceBboxStr);
log.info("图像区域坐标: {}", faceBboxStr);
}
}
// 解析动态区域坐标如果API返回中包含
if (output.has("ext_bbox")) {
JsonNode extBbox = output.get("ext_bbox");
if (extBbox.isArray()) {
String extBboxStr = extBbox.toString();
faceDetectLog.setExtBbox(extBboxStr);
log.info("动态区域坐标: {}", extBboxStr);
}
}
}
//emoji 开始
if (jsonResponse.has("output") && jsonResponse.get("output").has("ext_bbox_face")) {
String ext_bbox = jsonResponse.get("output").get("ext_bbox_face").toString();
faceDetectLog.setExtBbox(ext_bbox);
}
if (jsonResponse.has("output") && jsonResponse.get("output").has("bbox_face")) {
String bboxFace = jsonResponse.get("output").get("bbox_face").toString();
faceDetectLog.setFaceBbox(bboxFace);
}
//emoji 结束
// 记录请求ID
if (jsonResponse.has("request_id")) {
String apiRequestId = jsonResponse.get("request_id").asText();
log.info("API请求ID: {}", apiRequestId);
}
// 记录使用情况
if (jsonResponse.has("usage")) {
JsonNode usage = jsonResponse.get("usage");
if (usage.has("image_count")) {
int imageCount = usage.get("image_count").asInt();
log.info("处理的图片数量: {}", imageCount);
// 可以将image_count保存到数据库字段中如果有的话
faceDetectLog.setFaceCount(imageCount);
}
// 记录其他usage信息
log.info("使用情况: {}", usage.toString());
}
} else {
// HTTP状态码不是200直接标记为失败
faceDetectLog.setSuccess(false);
}
// 保存到数据库
boolean saved = saveFaceDetectLog(faceDetectLog);
if (saved) {
log.info("图像检测日志已保存请求ID: {}", requestId);
} else {
log.error("保存图像检测日志失败请求ID: {}", requestId);
}
return faceDetectLog;
} catch (HttpClientErrorException e) {
return handleError(faceDetectLog, e, "客户端错误 (4xx): " + e.getStatusCode(), startTime);
} catch (HttpServerErrorException e) {
return handleError(faceDetectLog, e, "服务器错误 (5xx): " + e.getStatusCode(), startTime);
} catch (Exception e) {
return handleError(faceDetectLog, e, "图像检测请求失败: " + e.getMessage(), startTime);
}
}
/**
* 处理错误并保存到数据库
*/
private FaceDetectLog handleError(FaceDetectLog faceDetectLog, Exception e, String errorMessage, long startTime) {
long endTime = System.currentTimeMillis();
long processingTime = endTime - startTime;
faceDetectLog.setResponseTime(LocalDateTime.now());
faceDetectLog.setSuccess(false);
faceDetectLog.setProcessingTimeMs(processingTime);
faceDetectLog.setErrorMessage(errorMessage);
if (e instanceof HttpClientErrorException) {
faceDetectLog.setStatusCode(((HttpClientErrorException) e).getStatusCode().value());
faceDetectLog.setResponseData(((HttpClientErrorException) e).getResponseBodyAsString());
} else if (e instanceof HttpServerErrorException) {
faceDetectLog.setStatusCode(((HttpServerErrorException) e).getStatusCode().value());
faceDetectLog.setResponseData(((HttpServerErrorException) e).getResponseBodyAsString());
}
log.error("图像检测失败: {}", errorMessage);
log.error("错误详情: {}", e.getMessage());
// 保存错误日志到数据库
try {
saveFaceDetectLog(faceDetectLog);
log.info("错误日志已保存请求ID: {}", faceDetectLog.getRequestId());
} catch (Exception saveException) {
log.error("保存错误日志失败: {}", saveException.getMessage());
}
return faceDetectLog;
}
/**
* 创建错误日志
*/
private FaceDetectLog createErrorLog(String imageUrl, String errorMessage) {
return createErrorLog(imageUrl, errorMessage, null, null, null);
}
/**
* 创建错误日志(带扩展信息)
*/
private FaceDetectLog createErrorLog(String imageUrl, String errorMessage, String ownerName, String ownerPhone, String avatarName) {
FaceDetectLog faceDetectLog = new FaceDetectLog();
faceDetectLog.setRequestId(UUID.randomUUID().toString());
faceDetectLog.setModel("liveportrait-detect");
faceDetectLog.setImageUrl(imageUrl);
faceDetectLog.setOwnerName(ownerName);
faceDetectLog.setOwnerPhone(ownerPhone);
faceDetectLog.setAvatarName(avatarName);
faceDetectLog.setRequestTime(LocalDateTime.now());
faceDetectLog.setResponseTime(LocalDateTime.now());
faceDetectLog.setSuccess(false);
faceDetectLog.setErrorMessage(errorMessage);
faceDetectLog.setFaceCount(0);
try {
saveFaceDetectLog(faceDetectLog);
} catch (Exception e) {
log.error("保存错误日志失败: {}", e.getMessage());
}
return faceDetectLog;
}
/**
* 分页查询图像检测日志
*/
@Override
public com.baomidou.mybatisplus.extension.plugins.pagination.Page<FaceDetectLog> getPageList(
Integer current, Integer size, Boolean success, String startTime, String endTime,
String ownerName, String ownerPhone, String avatarName) {
com.baomidou.mybatisplus.extension.plugins.pagination.Page<FaceDetectLog> page =
new com.baomidou.mybatisplus.extension.plugins.pagination.Page<>(current, size);
com.baomidou.mybatisplus.core.conditions.query.LambdaQueryWrapper<FaceDetectLog> queryWrapper =
new com.baomidou.mybatisplus.core.conditions.query.LambdaQueryWrapper<>();
// 添加查询条件
if (success != null) {
queryWrapper.eq(FaceDetectLog::getSuccess, success);
}
if (startTime != null && !startTime.trim().isEmpty()) {
queryWrapper.ge(FaceDetectLog::getRequestTime, startTime);
}
if (endTime != null && !endTime.trim().isEmpty()) {
queryWrapper.le(FaceDetectLog::getRequestTime, endTime);
}
if (ownerName != null && !ownerName.trim().isEmpty()) {
queryWrapper.like(FaceDetectLog::getOwnerName, ownerName);
}
if (ownerPhone != null && !ownerPhone.trim().isEmpty()) {
queryWrapper.like(FaceDetectLog::getOwnerPhone, ownerPhone);
}
if (avatarName != null && !avatarName.trim().isEmpty()) {
queryWrapper.like(FaceDetectLog::getAvatarName, avatarName);
}
// 按请求时间倒序排列
queryWrapper.orderByDesc(FaceDetectLog::getRequestTime);
return page(page, queryWrapper);
}
/**
* 获取统计信息
*/
@Override
public Map<String, Object> getStatistics(String startTime, String endTime) {
Map<String, Object> statistics = new HashMap<>();
// 构建查询条件
com.baomidou.mybatisplus.core.conditions.query.LambdaQueryWrapper<FaceDetectLog> queryWrapper =
new com.baomidou.mybatisplus.core.conditions.query.LambdaQueryWrapper<>();
// 时间范围筛选
if (startTime != null && !startTime.trim().isEmpty()) {
queryWrapper.ge(FaceDetectLog::getRequestTime, startTime);
}
if (endTime != null && !endTime.trim().isEmpty()) {
queryWrapper.le(FaceDetectLog::getRequestTime, endTime);
}
// 查询总数
long totalCount = count(queryWrapper);
// 查询成功数
com.baomidou.mybatisplus.core.conditions.query.LambdaQueryWrapper<FaceDetectLog> successWrapper =
new com.baomidou.mybatisplus.core.conditions.query.LambdaQueryWrapper<>();
// 时间范围筛选
if (startTime != null && !startTime.trim().isEmpty()) {
successWrapper.ge(FaceDetectLog::getRequestTime, startTime);
}
if (endTime != null && !endTime.trim().isEmpty()) {
successWrapper.le(FaceDetectLog::getRequestTime, endTime);
}
successWrapper.eq(FaceDetectLog::getSuccess, true);
long successCount = count(successWrapper);
// 查询失败数
long failureCount = totalCount - successCount;
// 计算成功率
double successRate = totalCount > 0 ? (double) successCount / totalCount * 100 : 0;
// 查询平均处理时间
java.util.List<FaceDetectLog> logs = list(queryWrapper);
double avgProcessingTime = logs.stream()
.filter(log -> log.getProcessingTimeMs() != null)
.mapToLong(FaceDetectLog::getProcessingTimeMs)
.average()
.orElse(0.0);
// 查询总图像数量
int totalFaceCount = logs.stream()
.filter(log -> log.getFaceCount() != null)
.mapToInt(FaceDetectLog::getFaceCount)
.sum();
// 构建统计结果
statistics.put("totalCount", totalCount);
statistics.put("successCount", successCount);
statistics.put("failureCount", failureCount);
statistics.put("successRate", Math.round(successRate * 100.0) / 100.0);
statistics.put("avgProcessingTimeMs", Math.round(avgProcessingTime));
statistics.put("totalFaceCount", totalFaceCount);
log.info("统计信息查询完成,总数: {}, 成功数: {}, 失败数: {}, 成功率: {}%",
totalCount, successCount, failureCount, successRate);
return statistics;
}
}