feat(facebody): 添加图片下载及base64重试机制

- 当添加人脸因无法访问URL图片失败时,自动下载图片并转换为base64后重试
- 新增downloadImageAsBase64方法用于图片下载与编码
- 替换阿里云OSS域名以支持内网访问
- 增加对png和jpg格式图片的支持
- 使用hutool库进行base64编码
- 添加详细的日志记录以便追踪重试过程
This commit is contained in:
2025-11-17 10:21:10 +08:00
parent a7a7e30364
commit 0c3ada97f9

View File

@@ -1,5 +1,6 @@
package com.ycwl.basic.facebody.adapter; package com.ycwl.basic.facebody.adapter;
import cn.hutool.core.codec.Base64;
import com.baidu.aip.face.AipFace; import com.baidu.aip.face.AipFace;
import com.ycwl.basic.facebody.entity.AddFaceResp; import com.ycwl.basic.facebody.entity.AddFaceResp;
import com.ycwl.basic.facebody.entity.BceFaceBodyConfig; import com.ycwl.basic.facebody.entity.BceFaceBodyConfig;
@@ -15,8 +16,13 @@ import lombok.extern.slf4j.Slf4j;
import org.json.JSONArray; import org.json.JSONArray;
import org.json.JSONObject; import org.json.JSONObject;
import javax.imageio.ImageIO;
import java.awt.image.BufferedImage;
import java.io.ByteArrayOutputStream;
import java.io.IOException;
import java.math.BigDecimal; import java.math.BigDecimal;
import java.math.RoundingMode; import java.math.RoundingMode;
import java.net.URL;
import java.util.ArrayList; import java.util.ArrayList;
import java.util.Collections; import java.util.Collections;
import java.util.HashMap; import java.util.HashMap;
@@ -152,10 +158,34 @@ public class BceFaceBodyAdapter implements IFaceBodyAdapter {
} catch (InterruptedException ignored) { } catch (InterruptedException ignored) {
} }
JSONObject response = client.addUser(faceUrl, "URL", dbName, entityId, options); JSONObject response = client.addUser(faceUrl, "URL", dbName, entityId, options);
if (response.getInt("error_code") == 0) { int errorCode = response.getInt("error_code");
if (errorCode == 0) {
AddFaceResp resp = new AddFaceResp(); AddFaceResp resp = new AddFaceResp();
resp.setScore(100f); resp.setScore(100f);
return resp; return resp;
} else if (errorCode == 222204) {
// error_code: 222204 表示无法正常访问URL图片,尝试下载并转换为base64后重试
log.warn("无法正常访问URL图片,错误码: 222204,尝试下载图片转base64后重试,URL: {}", faceUrl);
String base64Image = downloadImageAsBase64(faceUrl);
if (base64Image != null) {
try {
addEntityLimiter.acquire();
} catch (InterruptedException ignored) {
}
JSONObject retryResponse = client.addUser(base64Image, "BASE64", dbName, entityId, options);
if (retryResponse.getInt("error_code") == 0) {
log.info("使用base64重试添加人脸成功,entityId: {}", entityId);
AddFaceResp resp = new AddFaceResp();
resp.setScore(100f);
return resp;
} else {
log.warn("使用base64重试添加人脸仍失败!{}", retryResponse);
return null;
}
} else {
log.error("下载图片转base64失败,无法重试,URL: {}", faceUrl);
return null;
}
} else { } else {
log.warn("创建人脸失败!{}", response); log.warn("创建人脸失败!{}", response);
return null; return null;
@@ -395,7 +425,53 @@ public class BceFaceBodyAdapter implements IFaceBodyAdapter {
return client; return client;
} }
} }
/**
* 下载图片并转换为base64字符串
*
* @param imageUrl 图片URL
* @return base64编码的图片字符串,失败返回null
*/
private String downloadImageAsBase64(String imageUrl) {
BufferedImage image = null;
ByteArrayOutputStream baos = null;
try {
// 下载图片
URL url = new URL(imageUrl.replace("oss-cn-shanghai.aliyuncs.com", "oss-cn-shanghai-internal.aliyuncs.com"));
image = ImageIO.read(url);
if (image == null) {
log.error("无法读取图片,URL: {}", imageUrl);
return null;
}
// 转换为字节数组
baos = new ByteArrayOutputStream();
String format = "jpg";
if (imageUrl.toLowerCase().endsWith(".png")) {
format = "png";
}
ImageIO.write(image, format, baos);
byte[] imageBytes = baos.toByteArray();
// 编码为base64
return Base64.encode(imageBytes);
} catch (IOException e) {
log.error("下载图片或转换base64失败,URL: {}", imageUrl, e);
return null;
} finally {
if (image != null) {
image.flush();
}
if (baos != null) {
try {
baos.close();
} catch (IOException e) {
log.warn("关闭ByteArrayOutputStream失败", e);
}
}
}
}
private IRateLimiter getLimiter(LOCK_TYPE type) { private IRateLimiter getLimiter(LOCK_TYPE type) {
return switch (type) { return switch (type) {
case ADD_DB -> case ADD_DB ->