|
@@ -1,5 +1,8 @@
|
|
package cn.com.qmth.examcloud.starters.face.verify.service.baidu;
|
|
package cn.com.qmth.examcloud.starters.face.verify.service.baidu;
|
|
|
|
|
|
|
|
+import cn.com.qmth.examcloud.starters.face.verify.FaceVerifyProperties;
|
|
|
|
+import cn.com.qmth.examcloud.starters.face.verify.common.Constants;
|
|
|
|
+import cn.com.qmth.examcloud.starters.face.verify.common.FaceResult;
|
|
import cn.com.qmth.examcloud.starters.face.verify.common.HttpClientBuilder;
|
|
import cn.com.qmth.examcloud.starters.face.verify.common.HttpClientBuilder;
|
|
import cn.com.qmth.examcloud.starters.face.verify.common.JsonHelper;
|
|
import cn.com.qmth.examcloud.starters.face.verify.common.JsonHelper;
|
|
import okhttp3.*;
|
|
import okhttp3.*;
|
|
@@ -8,16 +11,13 @@ import org.slf4j.Logger;
|
|
import org.slf4j.LoggerFactory;
|
|
import org.slf4j.LoggerFactory;
|
|
|
|
|
|
import java.io.IOException;
|
|
import java.io.IOException;
|
|
-import java.util.ArrayList;
|
|
|
|
import java.util.List;
|
|
import java.util.List;
|
|
-import java.util.Map;
|
|
|
|
-import java.util.TreeMap;
|
|
|
|
|
|
|
|
public class BaiduApiHelper {
|
|
public class BaiduApiHelper {
|
|
|
|
|
|
private final static Logger log = LoggerFactory.getLogger(BaiduApiHelper.class);
|
|
private final static Logger log = LoggerFactory.getLogger(BaiduApiHelper.class);
|
|
|
|
|
|
- public static BaiduSession getAccessToken(String apiKey, String apiSecret, String apiUrl) {
|
|
|
|
|
|
+ public static BaiduSession getAccessToken(String apiKey, String apiSecret) {
|
|
if (StringUtils.isBlank(apiKey)) {
|
|
if (StringUtils.isBlank(apiKey)) {
|
|
throw new IllegalArgumentException("Baidu apiKey must be not empty.");
|
|
throw new IllegalArgumentException("Baidu apiKey must be not empty.");
|
|
}
|
|
}
|
|
@@ -26,11 +26,7 @@ public class BaiduApiHelper {
|
|
throw new IllegalArgumentException("Baidu apiSecret must be not empty.");
|
|
throw new IllegalArgumentException("Baidu apiSecret must be not empty.");
|
|
}
|
|
}
|
|
|
|
|
|
- if (StringUtils.isBlank(apiUrl)) {
|
|
|
|
- throw new IllegalArgumentException("Baidu apiUrl must be not empty.");
|
|
|
|
- }
|
|
|
|
-
|
|
|
|
- String requestUrl = String.format("%s?grant_type=client_credentials&client_id=%s&client_secret=%s", apiUrl, apiKey, apiSecret);
|
|
|
|
|
|
+ String requestUrl = String.format("%s?grant_type=client_credentials&client_id=%s&client_secret=%s", Constants.BAIDU_TOKEN_URL, apiKey, apiSecret);
|
|
Request.Builder request = new Request.Builder().url(requestUrl).get();
|
|
Request.Builder request = new Request.Builder().url(requestUrl).get();
|
|
|
|
|
|
try (Response response = HttpClientBuilder.getClient().newCall(request.build()).execute();
|
|
try (Response response = HttpClientBuilder.getClient().newCall(request.build()).execute();
|
|
@@ -52,66 +48,128 @@ public class BaiduApiHelper {
|
|
}
|
|
}
|
|
}
|
|
}
|
|
|
|
|
|
- public static BaiduResponse faceDetect(String accessToken, String apiUrl, String imageUrl) {
|
|
|
|
- if (StringUtils.isBlank(apiUrl)) {
|
|
|
|
- throw new IllegalArgumentException("Baidu apiUrl must be not empty.");
|
|
|
|
|
|
+ public static FaceResult faceDetect(FaceVerifyProperties properties, String jsonParams) {
|
|
|
|
+ if (StringUtils.isBlank(jsonParams)) {
|
|
|
|
+ throw new IllegalArgumentException("Baidu api params must be not empty.");
|
|
}
|
|
}
|
|
|
|
|
|
- if (StringUtils.isBlank(imageUrl)) {
|
|
|
|
- throw new IllegalArgumentException("face imageUrl must be not empty.");
|
|
|
|
|
|
+ BaiduSession session = BaiduApiHelper.getAccessToken(properties.getBaiduKey(), properties.getBaiduSecret());
|
|
|
|
+ String accessToken = session.getAccess_token();
|
|
|
|
+
|
|
|
|
+ String requestUrl = String.format("%s?access_token=%s", Constants.BAIDU_FACE_DETECT_URL, accessToken);
|
|
|
|
+ RequestBody formBody = FormBody.create(MediaType.parse(Constants.JSON_CONTENT_TYPE), jsonParams);
|
|
|
|
+
|
|
|
|
+ BaiduResponse response = callApi(requestUrl, formBody);
|
|
|
|
+ return parseFaceDetectResult(response);
|
|
|
|
+ }
|
|
|
|
+
|
|
|
|
+ public static FaceResult faceDetectUseLocalApi(FaceVerifyProperties properties, String jsonParams) {
|
|
|
|
+ if (StringUtils.isBlank(jsonParams)) {
|
|
|
|
+ throw new IllegalArgumentException("Baidu api params must be not empty.");
|
|
}
|
|
}
|
|
|
|
|
|
- List<Map<String, String>> params = new ArrayList<>();
|
|
|
|
- Map<String, String> imageData = new TreeMap<>();
|
|
|
|
- // image_type: URL、BASE64、FACE_TOKEN
|
|
|
|
- imageData.put("image_type", "URL");
|
|
|
|
- imageData.put("image", imageUrl);
|
|
|
|
- params.add(imageData);
|
|
|
|
- String jsonParams = new JsonHelper().toJson(params);
|
|
|
|
|
|
+ String requestUrl = String.format("%s?appid=%s", properties.getBaiduLocalUrlPrefix() + Constants.BAIDU_FACE_DETECT_LOCAL_URL, properties.getBaiduLocalAppId());
|
|
|
|
+ RequestBody formBody = FormBody.create(MediaType.parse(Constants.JSON_CONTENT_TYPE), jsonParams);
|
|
|
|
|
|
- final String contentType = "application/json; charset=utf-8";
|
|
|
|
- RequestBody formBody = FormBody.create(MediaType.parse(contentType), jsonParams);
|
|
|
|
|
|
+ BaiduResponse response = callApi(requestUrl, formBody);
|
|
|
|
+ return parseFaceDetectResult(response);
|
|
|
|
+ }
|
|
|
|
|
|
- String requestUrl = String.format("%s?access_token=%s", apiUrl, accessToken);
|
|
|
|
- Request.Builder request = new Request.Builder().url(requestUrl).post(formBody);
|
|
|
|
|
|
+ public static FaceResult faceCompare(FaceVerifyProperties properties, String jsonParams) {
|
|
|
|
+ if (StringUtils.isBlank(jsonParams)) {
|
|
|
|
+ throw new IllegalArgumentException("Baidu api params must be not empty.");
|
|
|
|
+ }
|
|
|
|
|
|
- return callApi(apiUrl, request);
|
|
|
|
|
|
+ BaiduSession session = BaiduApiHelper.getAccessToken(properties.getBaiduKey(), properties.getBaiduSecret());
|
|
|
|
+ String accessToken = session.getAccess_token();
|
|
|
|
+
|
|
|
|
+ String requestUrl = String.format("%s?access_token=%s", Constants.BAIDU_FACE_COMPARE_URL, accessToken);
|
|
|
|
+ RequestBody formBody = FormBody.create(MediaType.parse(Constants.JSON_CONTENT_TYPE), jsonParams);
|
|
|
|
+
|
|
|
|
+ BaiduResponse response = callApi(requestUrl, formBody);
|
|
|
|
+ return parseFaceCompareResult(response);
|
|
}
|
|
}
|
|
|
|
|
|
- public static BaiduResponse faceCompare(String accessToken, String apiUrl, String imageUrl, String imageUrl2) {
|
|
|
|
- if (StringUtils.isBlank(apiUrl)) {
|
|
|
|
- throw new IllegalArgumentException("Baidu apiUrl must be not empty.");
|
|
|
|
|
|
+ public static FaceResult faceCompareUseLocalApi(FaceVerifyProperties properties, String jsonParams) {
|
|
|
|
+ if (StringUtils.isBlank(jsonParams)) {
|
|
|
|
+ throw new IllegalArgumentException("Baidu api params must be not empty.");
|
|
|
|
+ }
|
|
|
|
+
|
|
|
|
+ String requestUrl = String.format("%s?appid=%s", properties.getBaiduLocalUrlPrefix() + Constants.BAIDU_FACE_COMPARE_LOCAL_URL, properties.getBaiduLocalAppId());
|
|
|
|
+ RequestBody formBody = FormBody.create(MediaType.parse(Constants.JSON_CONTENT_TYPE), jsonParams);
|
|
|
|
+
|
|
|
|
+ BaiduResponse response = callApi(requestUrl, formBody);
|
|
|
|
+ return parseFaceCompareResult(response);
|
|
|
|
+ }
|
|
|
|
+
|
|
|
|
+ private static FaceResult parseFaceDetectResult(BaiduResponse response) {
|
|
|
|
+ FaceResult result = new FaceResult();
|
|
|
|
+ result.setPass(false);
|
|
|
|
+ result.setApiLimit(false);
|
|
|
|
+
|
|
|
|
+ if (response.getError_code() != 0) {
|
|
|
|
+ result.setError(response.getError_code() + " - " + response.getError_msg());
|
|
|
|
+
|
|
|
|
+ // 请求并发超限(约10个/秒)
|
|
|
|
+ if (response.getError_code() == 18) {
|
|
|
|
+ result.setApiLimit(true);
|
|
|
|
+ }
|
|
|
|
+ return result;
|
|
}
|
|
}
|
|
|
|
|
|
- if (StringUtils.isBlank(imageUrl)) {
|
|
|
|
- throw new IllegalArgumentException("face imageUrl must be not empty.");
|
|
|
|
|
|
+ BaiduResult data = response.getResult();
|
|
|
|
+ if (data != null) {
|
|
|
|
+ double faceLiveness = data.getFace_liveness() != null ? data.getFace_liveness() : 0d;
|
|
|
|
+
|
|
|
|
+ result.setScore(faceLiveness);
|
|
|
|
+ result.setThresholds(new JsonHelper().toJson(data.getThresholds()));
|
|
|
|
+
|
|
|
|
+ if (data.getFace_num() != null) {
|
|
|
|
+ result.setFaceNum(data.getFace_num());
|
|
|
|
+ } else {
|
|
|
|
+ List<BaiduFace> faces = data.getFace_list();
|
|
|
|
+ result.setFaceNum(faces != null ? faces.size() : 0);
|
|
|
|
+ }
|
|
|
|
+
|
|
|
|
+ // 活体分数值,推荐阈值0.393241
|
|
|
|
+ if (faceLiveness >= 0.39d) {
|
|
|
|
+ result.setPass(true);
|
|
|
|
+ }
|
|
}
|
|
}
|
|
|
|
|
|
- if (StringUtils.isBlank(imageUrl2)) {
|
|
|
|
- throw new IllegalArgumentException("face imageUrl2 must be not empty.");
|
|
|
|
|
|
+ return result;
|
|
|
|
+ }
|
|
|
|
+
|
|
|
|
+ private static FaceResult parseFaceCompareResult(BaiduResponse response) {
|
|
|
|
+ FaceResult result = new FaceResult();
|
|
|
|
+ result.setPass(false);
|
|
|
|
+ result.setApiLimit(false);
|
|
|
|
+
|
|
|
|
+ if (response.getError_code() != 0) {
|
|
|
|
+ result.setError(response.getError_code() + " - " + response.getError_msg());
|
|
|
|
+
|
|
|
|
+ // 请求并发超限(约10个/秒)
|
|
|
|
+ if (response.getError_code() == 18) {
|
|
|
|
+ result.setApiLimit(true);
|
|
|
|
+ }
|
|
|
|
+ return result;
|
|
}
|
|
}
|
|
|
|
|
|
- List<Map<String, String>> params = new ArrayList<>();
|
|
|
|
- Map<String, String> imageData = new TreeMap<>();
|
|
|
|
- imageData.put("image_type", "URL");
|
|
|
|
- imageData.put("image", imageUrl);
|
|
|
|
- params.add(imageData);
|
|
|
|
- Map<String, String> imageData2 = new TreeMap<>();
|
|
|
|
- imageData2.put("image_type", "URL");
|
|
|
|
- imageData2.put("image", imageUrl2);
|
|
|
|
- params.add(imageData2);
|
|
|
|
- String jsonParams = new JsonHelper().toJson(params);
|
|
|
|
-
|
|
|
|
- final String contentType = "application/json; charset=utf-8";
|
|
|
|
- RequestBody formBody = FormBody.create(MediaType.parse(contentType), jsonParams);
|
|
|
|
-
|
|
|
|
- String requestUrl = String.format("%s?access_token=%s", apiUrl, accessToken);
|
|
|
|
- Request.Builder request = new Request.Builder().url(requestUrl).post(formBody);
|
|
|
|
|
|
+ BaiduResult data = response.getResult();
|
|
|
|
+ if (data != null) {
|
|
|
|
+ result.setScore(data.getScore());
|
|
|
|
|
|
- return callApi(apiUrl, request);
|
|
|
|
|
|
+ // 人脸相似度得分,推荐阈值80分
|
|
|
|
+ if (data.getScore() != null && data.getScore() >= 80d) {
|
|
|
|
+ result.setPass(true);
|
|
|
|
+ }
|
|
|
|
+ }
|
|
|
|
+
|
|
|
|
+ return result;
|
|
}
|
|
}
|
|
|
|
|
|
- private static BaiduResponse callApi(String apiUrl, Request.Builder request) {
|
|
|
|
|
|
+ private static BaiduResponse callApi(String requestUrl, RequestBody formBody) {
|
|
|
|
+ Request.Builder request = new Request.Builder().url(requestUrl).post(formBody);
|
|
try (Response response = HttpClientBuilder.getClient().newCall(request.build()).execute();
|
|
try (Response response = HttpClientBuilder.getClient().newCall(request.build()).execute();
|
|
ResponseBody body = response.body();) {
|
|
ResponseBody body = response.body();) {
|
|
String bodyStr = body.string();
|
|
String bodyStr = body.string();
|
|
@@ -125,10 +183,11 @@ public class BaiduApiHelper {
|
|
}
|
|
}
|
|
}
|
|
}
|
|
|
|
|
|
- log.warn("[baidu] url:{} response:{} body:{}", apiUrl, response.code(), bodyStr);
|
|
|
|
|
|
+ log.warn("[baidu] url:{} response:{} body:{}", requestUrl, response.code(), bodyStr);
|
|
} catch (IOException e) {
|
|
} catch (IOException e) {
|
|
log.error(e.getMessage(), e);
|
|
log.error(e.getMessage(), e);
|
|
}
|
|
}
|
|
|
|
+
|
|
throw new RuntimeException("[baidu] 接口调用异常!");
|
|
throw new RuntimeException("[baidu] 接口调用异常!");
|
|
}
|
|
}
|
|
|
|
|