|
|
@@ -2,11 +2,18 @@ package com.github.microservice.auth.server.core.service.local;
|
|
|
|
|
|
import com.github.microservice.auth.client.content.ResultContent;
|
|
|
import com.github.microservice.auth.client.content.ResultState;
|
|
|
+import com.github.microservice.auth.server.core.conf.RedisearchConf;
|
|
|
+import com.github.microservice.auth.server.core.model.RedisearchResultModel;
|
|
|
import com.github.microservice.auth.client.model.UserFaceQueryModel;
|
|
|
import com.github.microservice.auth.client.model.UserFaceUploadModel;
|
|
|
import com.github.microservice.auth.client.service.UserFaceService;
|
|
|
import com.github.microservice.auth.server.core.dao.UserDao;
|
|
|
+import com.github.microservice.auth.server.core.dao.UserFaceDao;
|
|
|
import com.github.microservice.auth.server.core.domain.User;
|
|
|
+import com.github.microservice.auth.server.core.domain.UserFace;
|
|
|
+import com.github.microservice.auth.server.core.model.ResultsModel;
|
|
|
+import com.github.microservice.auth.server.core.util.FaceUtil;
|
|
|
+import com.github.microservice.core.util.JsonUtil;
|
|
|
import com.mongodb.client.gridfs.GridFSFindIterable;
|
|
|
import com.mongodb.client.gridfs.model.GridFSFile;
|
|
|
import jakarta.validation.constraints.NotNull;
|
|
|
@@ -18,11 +25,12 @@ import org.springframework.beans.factory.annotation.Autowired;
|
|
|
import org.springframework.beans.factory.annotation.Value;
|
|
|
import org.springframework.data.mongodb.core.query.Criteria;
|
|
|
import org.springframework.data.mongodb.core.query.Query;
|
|
|
-import org.springframework.data.mongodb.gridfs.GridFsResource;
|
|
|
import org.springframework.data.mongodb.gridfs.GridFsTemplate;
|
|
|
import org.springframework.security.crypto.password.PasswordEncoder;
|
|
|
import org.springframework.stereotype.Service;
|
|
|
import org.springframework.web.client.RestTemplate;
|
|
|
+import org.springframework.web.multipart.MultipartFile;
|
|
|
+import redis.clients.jedis.JedisPooled;
|
|
|
|
|
|
import javax.imageio.ImageIO;
|
|
|
import java.awt.*;
|
|
|
@@ -31,6 +39,9 @@ import java.io.ByteArrayInputStream;
|
|
|
import java.io.ByteArrayOutputStream;
|
|
|
import java.io.IOException;
|
|
|
import java.io.InputStream;
|
|
|
+import java.math.BigDecimal;
|
|
|
+import java.net.http.HttpResponse;
|
|
|
+import java.nio.ByteBuffer;
|
|
|
import java.util.*;
|
|
|
import java.util.List;
|
|
|
|
|
|
@@ -44,6 +55,9 @@ public class UserFaceServiceImpl implements UserFaceService {
|
|
|
@Autowired
|
|
|
GridFsTemplate gridFsTemplate;
|
|
|
|
|
|
+ @Autowired
|
|
|
+ UserFaceDao userFaceDao;
|
|
|
+
|
|
|
@Autowired
|
|
|
RestTemplate restTemplate;
|
|
|
|
|
|
@@ -55,6 +69,8 @@ public class UserFaceServiceImpl implements UserFaceService {
|
|
|
@Autowired
|
|
|
private PasswordEncoder passwordEncoder;
|
|
|
|
|
|
+ @Autowired
|
|
|
+ RedisearchConf redisearchConf;
|
|
|
|
|
|
/**
|
|
|
* 上传人脸图片
|
|
|
@@ -64,37 +80,146 @@ public class UserFaceServiceImpl implements UserFaceService {
|
|
|
*/
|
|
|
@SneakyThrows
|
|
|
public ResultContent<String> upload(UserFaceUploadModel userFaceUploadModel) {
|
|
|
+
|
|
|
+ if (userFaceUploadModel.getFile().isEmpty()) {
|
|
|
+ return ResultContent.build(ResultState.Fail);
|
|
|
+ }
|
|
|
+
|
|
|
User user = userDao.findTop1ById(userFaceUploadModel.getUserId());
|
|
|
if (user == null) {
|
|
|
return ResultContent.build(ResultState.UserNotExists);
|
|
|
}
|
|
|
- //TODO 调整图片大小
|
|
|
- byte[] bytes = imageResizer(userFaceUploadModel.getUserFace());
|
|
|
- //TODO 上传人脸库,对比成功后入库
|
|
|
- @Cleanup ByteArrayInputStream byteArrayInputStream = new ByteArrayInputStream(bytes);
|
|
|
- String fileId = gridFsTemplate.store(byteArrayInputStream, UUID.randomUUID().toString(),Map.of("userId", userFaceUploadModel.getUserId())).toHexString();
|
|
|
-
|
|
|
- List<String> facePic = user.getFacePic();
|
|
|
- if (facePic == null || facePic.isEmpty()) {
|
|
|
- facePic = new ArrayList<>();
|
|
|
- }
|
|
|
- if (StringUtils.isNotBlank(userFaceUploadModel.getUpdateFaceFileId())){
|
|
|
+ boolean isUpdate = StringUtils.isNotBlank(userFaceUploadModel.getUpdateFaceFileId());
|
|
|
+ if (isUpdate) {
|
|
|
//替换原人脸图片
|
|
|
- if (!facePic.contains(userFaceUploadModel.getUpdateFaceFileId())){
|
|
|
+ if (userFaceDao.existsByUserIdAndFaceFSId(userFaceUploadModel.getUserId(), userFaceUploadModel.getUpdateFaceFileId())) {
|
|
|
return ResultContent.build(ResultState.FaceNotExists);
|
|
|
}
|
|
|
- int index = facePic.indexOf(userFaceUploadModel.getUpdateFaceFileId());
|
|
|
- facePic.set(index, fileId);
|
|
|
- }else {
|
|
|
- facePic.add(fileId);
|
|
|
}
|
|
|
- user.setFacePic(facePic);
|
|
|
- userDao.save(user);
|
|
|
+
|
|
|
+ MultipartFile file = userFaceUploadModel.getFile();
|
|
|
+ InputStream inputStream = file.getInputStream();
|
|
|
+
|
|
|
+
|
|
|
+ //TODO 调整图片大小
|
|
|
+// byte[] bytes = imageResizer(userFaceUploadModel.getUserFace());
|
|
|
+ //TODO 上传人脸库,获取向量
|
|
|
+ HttpResponse<String> response = FaceUtil.uploadFs("http://127.0.0.1:5001/v2/represent", inputStream, "yunet");
|
|
|
+
|
|
|
+ if (response.statusCode() != 200) {
|
|
|
+ return ResultContent.build(ResultState.Fail, "人脸特征提取失败");
|
|
|
+ }
|
|
|
+
|
|
|
+ final String body = response.body();
|
|
|
+
|
|
|
+ ResultsModel resultsModel = JsonUtil.toObject(body, ResultsModel.class);
|
|
|
+ System.out.println(resultsModel);
|
|
|
+
|
|
|
+
|
|
|
+
|
|
|
+ System.out.println(body);
|
|
|
+ List<Float> embedding = resultsModel.getResults().get(0).getEmbedding();
|
|
|
+
|
|
|
+
|
|
|
+
|
|
|
+ JedisPooled jedis = new JedisPooled(redisearchConf.getHost(), redisearchConf.getPort(), null, redisearchConf.getPassword());
|
|
|
+
|
|
|
+ // 动态设置变量
|
|
|
+ String indexName = redisearchConf.getIndexName();
|
|
|
+ String prefix = redisearchConf.getPrefix();
|
|
|
+ String fieldName = redisearchConf.getFieldName();
|
|
|
+ String dim = redisearchConf.getDim();
|
|
|
+ initIndex(jedis, indexName, prefix, fieldName, dim);
|
|
|
+
|
|
|
+
|
|
|
+ // 将 List<Float> 转换为 float[]
|
|
|
+ float[] vector = listToFloatArray(embedding);
|
|
|
+ // 归一化向量
|
|
|
+ double norm = calculateNorm(vector);
|
|
|
+ for (int i = 0; i < vector.length; i++) {
|
|
|
+ vector[i] /= norm;
|
|
|
+ }
|
|
|
+
|
|
|
+ // 转换为字节数组 (FLOAT32,每个值占 4 字节)
|
|
|
+ ByteBuffer buffer = ByteBuffer.allocate(vector.length * 4);
|
|
|
+ for (float value : vector) {
|
|
|
+ buffer.putFloat(value);
|
|
|
+ }
|
|
|
+
|
|
|
+ String key = prefix + user.getId() + System.currentTimeMillis();
|
|
|
+
|
|
|
+ long hset = jedis.hset(key.getBytes(), fieldName.getBytes(), buffer.array());
|
|
|
+
|
|
|
+ System.out.println(hset);
|
|
|
+ jedis.close();
|
|
|
+ //图片入库
|
|
|
+ String fileId = gridFsTemplate.store(inputStream, UUID.randomUUID().toString(), Map.of("userId", userFaceUploadModel.getUserId())).toHexString();
|
|
|
+ UserFace userFace = new UserFace();
|
|
|
+ if (isUpdate) {
|
|
|
+ userFace = userFaceDao.findTopByUserIdAndFaceFSId(userFaceUploadModel.getUserId(), userFaceUploadModel.getUpdateFaceFileId());
|
|
|
+ }
|
|
|
+ //向量入库
|
|
|
+ userFace.setUserId(user.getId());
|
|
|
+ userFace.setFaceFSId(fileId);
|
|
|
+ //设置向量
|
|
|
+ userFace.setVector(embedding);
|
|
|
+ userFace.setFaceDataKey(key);
|
|
|
+ userFaceDao.save(userFace);
|
|
|
return ResultContent.buildContent(fileId);
|
|
|
}
|
|
|
|
|
|
+ private static void initIndex(JedisPooled jedis, String indexName, String prefix, String fieldName, String dim) {
|
|
|
+ try {
|
|
|
+ Map<String, Object> stringObjectMap = jedis.ftInfo(indexName);
|
|
|
+ //TODO 检查参数是否正确
|
|
|
+ }catch (Exception e) {
|
|
|
+ //创建索引
|
|
|
+ // Lua 脚本模板
|
|
|
+ String createIndexScript = "local indexName = KEYS[1] " +
|
|
|
+ "local prefix = KEYS[2] " +
|
|
|
+ "local fieldName = KEYS[3] " +
|
|
|
+ "local dim = ARGV[1] " +
|
|
|
+ "redis.call('FT.CREATE', indexName, 'ON', 'HASH', 'PREFIX', '1', prefix, " +
|
|
|
+ "'SCHEMA', fieldName, 'VECTOR', 'FLAT', '6', " +
|
|
|
+ "'TYPE', 'FLOAT32', 'DIM', dim, 'DISTANCE_METRIC', 'COSINE')";
|
|
|
+
|
|
|
+
|
|
|
+ String a = """
|
|
|
+
|
|
|
+ """;
|
|
|
+
|
|
|
+ // 执行 Lua 脚本并传递变量
|
|
|
+ Object result = jedis.eval(createIndexScript,
|
|
|
+ // KEYS 参数:索引名、前缀、字段名
|
|
|
+ List.of(indexName, prefix, fieldName), List.of(dim));
|
|
|
+ System.out.println("Index created successfully: " + result);
|
|
|
+ }
|
|
|
+ }
|
|
|
+
|
|
|
+
|
|
|
+ private static float calculateNorm(float[] vector) {
|
|
|
+ float sum = 0;
|
|
|
+ for (float v : vector) {
|
|
|
+ sum += v * v; // 对每个分量平方求和
|
|
|
+ }
|
|
|
+ return (float) Math.sqrt(sum); // 求平方和的平方根
|
|
|
+ }
|
|
|
+
|
|
|
+ public static float[] listToFloatArray(List<Float> list) {
|
|
|
+ // 创建一个与 List 大小相同的 float 数组
|
|
|
+ float[] array = new float[list.size()];
|
|
|
+
|
|
|
+ // 使用普通的 for 循环将 List 中的每个元素放入数组中
|
|
|
+ for (int i = 0; i < list.size(); i++) {
|
|
|
+ array[i] = list.get(i); // 自动拆箱,将 Float 转换为 float
|
|
|
+ }
|
|
|
+
|
|
|
+ return array;
|
|
|
+ }
|
|
|
+
|
|
|
/**
|
|
|
* 删除用户指定人脸图片
|
|
|
+ *
|
|
|
* @param userId
|
|
|
* @param faceFileId
|
|
|
* @return
|
|
|
@@ -105,37 +230,39 @@ public class UserFaceServiceImpl implements UserFaceService {
|
|
|
return ResultContent.build(ResultState.UserNotExists);
|
|
|
}
|
|
|
|
|
|
- List<String> facePic = user.getFacePic();
|
|
|
- if (facePic == null || facePic.isEmpty()) {
|
|
|
+ UserFace userFace = userFaceDao.findTopByUserIdAndFaceFSId(userId, faceFileId);
|
|
|
+ if (userFace == null) {
|
|
|
return ResultContent.build(ResultState.FaceNotExists);
|
|
|
}
|
|
|
|
|
|
- if (!facePic.contains(faceFileId)) {
|
|
|
- return ResultContent.build(ResultState.FaceNotExists);
|
|
|
- }
|
|
|
+ //删除人脸库的人脸
|
|
|
+ JedisPooled jedis = new JedisPooled(redisearchConf.getHost(), redisearchConf.getPort(), null, redisearchConf.getPassword());
|
|
|
|
|
|
- facePic.remove(faceFileId);
|
|
|
- user.setFacePic(facePic);
|
|
|
- userDao.save(user);
|
|
|
+ long del = jedis.del(userFace.getFaceDataKey());
|
|
|
+ if (del == 0) {
|
|
|
+ log.error("人脸库删除数据失败:key:{}", userFace.getFaceDataKey());
|
|
|
+ return ResultContent.build(ResultState.Fail);
|
|
|
+ }
|
|
|
+ userFaceDao.deleteById(userFace.getId());
|
|
|
return ResultContent.build(ResultState.Success);
|
|
|
}
|
|
|
|
|
|
/**
|
|
|
* 获取用户人脸认证图片
|
|
|
+ *
|
|
|
* @param userId
|
|
|
* @return
|
|
|
*/
|
|
|
@SneakyThrows
|
|
|
- public ResultContent<List<UserFaceQueryModel>> get(String userId){
|
|
|
- User user = userDao.findTop1ById(userId);
|
|
|
- if (user == null) {
|
|
|
- return ResultContent.build(ResultState.UserNotExists);
|
|
|
- }
|
|
|
+ public ResultContent<List<UserFaceQueryModel>> get(String userId) {
|
|
|
//初始化返回结果
|
|
|
List<UserFaceQueryModel> userFaceBase64List = new ArrayList<>();
|
|
|
|
|
|
- List<String> facePic = user.getFacePic();
|
|
|
- if (facePic != null && !facePic.isEmpty()) {
|
|
|
+ List<UserFace> userFaceList = userFaceDao.findByUserId(userId);
|
|
|
+
|
|
|
+ List<String> facePic = userFaceList.stream().map(UserFace::getFaceFSId).toList();
|
|
|
+
|
|
|
+ if (!facePic.isEmpty()) {
|
|
|
Query query = new Query(Criteria.where("_id").in(facePic));
|
|
|
GridFSFindIterable gridFSFiles = gridFsTemplate.find(query);
|
|
|
for (GridFSFile gridFS : gridFSFiles) {
|
|
|
@@ -150,9 +277,140 @@ public class UserFaceServiceImpl implements UserFaceService {
|
|
|
return ResultContent.buildContent(userFaceBase64List);
|
|
|
}
|
|
|
|
|
|
- public ResultContent<String> matches(String userFace){
|
|
|
+ /**
|
|
|
+ * 对比人脸图片
|
|
|
+ *
|
|
|
+ * @param
|
|
|
+ * @return
|
|
|
+ */
|
|
|
+ @SneakyThrows
|
|
|
+ public ResultContent<Object> matches(MultipartFile file) {
|
|
|
+ //TODO 上传人脸服务,获取向量
|
|
|
+ InputStream inputStream = file.getInputStream();
|
|
|
+
|
|
|
+ //TODO 调整图片大小
|
|
|
+// byte[] bytes = imageResizer(userFaceUploadModel.getUserFace());
|
|
|
+ //TODO 上传人脸库,获取向量
|
|
|
+ HttpResponse<String> response = FaceUtil.uploadFs("http://127.0.0.1:5001/v2/represent", inputStream, "yunet");
|
|
|
+
|
|
|
+ if (response.statusCode() != 200) {
|
|
|
+ return ResultContent.build(ResultState.Fail, "人脸特征提取失败");
|
|
|
+ }
|
|
|
+
|
|
|
+ final String body = response.body();
|
|
|
+
|
|
|
+ ResultsModel resultsModel = JsonUtil.toObject(body, ResultsModel.class);
|
|
|
+ System.out.println(resultsModel);
|
|
|
+
|
|
|
+
|
|
|
+
|
|
|
+ System.out.println(body);
|
|
|
+ List<Float> embedding = resultsModel.getResults().get(0).getEmbedding();
|
|
|
+ float[] vector = listToFloatArray(embedding);
|
|
|
|
|
|
- return ResultContent.buildContent("userId");
|
|
|
+ float norm = calculateNorm(vector);
|
|
|
+ for (int i = 0; i < vector.length; i++) {
|
|
|
+ vector[i] /= norm;
|
|
|
+ }
|
|
|
+
|
|
|
+ // 转换为字节数组 (FLOAT32,每个值占 4 字节)
|
|
|
+ ByteBuffer buffer = ByteBuffer.allocate(vector.length * 4);
|
|
|
+ for (float value : vector) {
|
|
|
+ buffer.putFloat(value);
|
|
|
+ }
|
|
|
+ // 打印字节数组的内容
|
|
|
+ byte[] queryVector = buffer.array();
|
|
|
+ System.out.println("queryVector.length");
|
|
|
+ System.out.println(queryVector.length);
|
|
|
+
|
|
|
+ // 定义查询参数
|
|
|
+ String indexName = redisearchConf.getIndexName();
|
|
|
+ String prefix = redisearchConf.getPrefix();
|
|
|
+ String fieldName = redisearchConf.getFieldName();
|
|
|
+ String dim = redisearchConf.getDim();
|
|
|
+// String queryVectorString = "\x8d5\xf7=\x91w:=*\x19h=\x05u\xc8=\xfa\x06\xb0=+\x00\xa8=\x96\x9b\x02>\xd5\xb4\x19>\xf1Pf=\xb5U\xf7=\xbc\xaf\x10>\xd9\x96\x18>\xa5hk=\xcd\xd3\x83=\x86\xcd\x18>\xbd\x80\x0b>A$\xf1=\xb2\xcf\xc5=K\xd4\xe2=\x83c\x01>\x02\x85\xbb=c$'=\x00-\x14>\x0c[i=\x80\x0b\xaf=\x15r\x0c>\xb2\x1f\xbf<\xe78\x8e=\x9b\xb9\xdf=\xce\xd9\xa3=\xe7\xaa\r>\xee\\\xaa=\x83\x95g=g/R=x\xc0\x0b>\xfd\xe7\x07>M\xb8\x0f=\x05\xbcA=q\x0e\xbd=R\x98\x8c;b\xfe\x85=\xea%+=\xe7\x98\x81:0H\x07>\xd9g\x04>\xe5\xe3\x8e=oM]=%\xbe\x92<\x1e\xf7\x05>\x11\xa9\x1a>\xce1\xe9<Z\x8d\x0e>\xe0<\x07>\xcar\x86=\xde\x0e\x9e=l\x8e\xf6=\xa9\x04\xa7=7\xe9G=\n[\x05<\xcd\xb3\x1c=\xf26\xe2=\xfd\xbd\xa4=\x94\x95\xea=\xb3\x9f\xa7<*Z\xfb;o\xbb\xb7<\xae\xea\xdb=\x03\x82\xcb<\xc8\x12\x1a<\xfa\xf9\x91<\xacJ\x18=\x18\xcb\xb0=n\x87\x92=6j\xf0=\xa7\xf0\x92<]!\xb4=\xf8\x01\x85=\xaf\xfa\xd7=\xbbE\xe5;f\x9d\xeb<^\xe1\x00>\xa3\xb9\x93=\x83\xcb\x14>\xdb\x86\x1a>\xe1\xa0\xd7=Cu*=9\xfd\x8f=e\xe2\xe7<y1.=2T\x91=59\x92=\xd8\xb5\xbd=\xd5\xf1\xa1=\xf4\xd6\x08>m\xd3K<\x1b\xc5M=\x93#\xb2=\xc0\x8b\xb4=\xa0Ph=\xe4s\x92=\xd7\x93\xb4=\xa3x\\;Q\x84\x08>\x8b&\xdc<a\x0e\x1d=\x83\x9c\x9e<\x9a\x84\xac<\xceS\xdf=\x8bT\xab;\xa7\xfd\r=\x88j\x10<\xcd\x07\xee<\x07\x8e\x81<t^\xdc=\xcf\xcf\xbd=\xeb\x92\xa1<[\x88\xd7=\xf0\xbb\x00>\x8e*\x18>\x82\xad\x11>yG\xbb<g\x07\x06>\xa08\x8d<\x01C\x1b>\xc7\xfd:=\x0b\x93\x10;\xbce>=\xb9\xdba=";
|
|
|
+ String topK = "1"; // 返回Top 10个结果
|
|
|
+// String vectorField = "doc_embedding"; // 向量字段名称
|
|
|
+
|
|
|
+ String queryScript = "local indexName = KEYS[1] "
|
|
|
+ + "local queryVector = ARGV[1] "
|
|
|
+ + "local topK = tonumber(ARGV[2]) "
|
|
|
+ + "local vectorField = ARGV[3] "
|
|
|
+ + "local query = '*=>[KNN ' .. topK .. ' @' .. vectorField .. ' $BLOB AS score]' "
|
|
|
+ + "local result = redis.call('FT.SEARCH', indexName, query, "
|
|
|
+ + "'PARAMS', '2', 'BLOB', queryVector, "
|
|
|
+ + "'RETURN', '1', 'score', "
|
|
|
+ + "'SORTBY', 'score', "
|
|
|
+ + "'DIALECT', '2') "
|
|
|
+ + "return result";
|
|
|
+ // 执行Redis查询
|
|
|
+
|
|
|
+
|
|
|
+ JedisPooled jedis = new JedisPooled( redisearchConf.getHost(), redisearchConf.getPort(), null, redisearchConf.getPassword());
|
|
|
+
|
|
|
+ // 动态设置变量
|
|
|
+
|
|
|
+ initIndex(jedis, indexName, prefix, fieldName, dim);
|
|
|
+
|
|
|
+ Object result = jedis.eval(queryScript.getBytes(), 1, indexName.getBytes(), queryVector, topK.getBytes(), fieldName.getBytes());
|
|
|
+ // 关闭连接
|
|
|
+ jedis.close();
|
|
|
+ // 打印结果
|
|
|
+ System.out.println("Query Result: " + JsonUtil.toJson(result));
|
|
|
+ RedisearchResultModel redisearchResultModel = processQueryResult(result);
|
|
|
+ //TODO 解析结果,返回userId
|
|
|
+ if (redisearchResultModel.getCount() == 0L) {
|
|
|
+ return ResultContent.build(ResultState.FaceNoMatches);
|
|
|
+ }
|
|
|
+
|
|
|
+ if (redisearchResultModel.getScoreValue().equals("nan") || redisearchResultModel.getScoreValue().equals("-nan")) {
|
|
|
+ return ResultContent.build(ResultState.FaceNoMatches);
|
|
|
+ }
|
|
|
+
|
|
|
+ BigDecimal scoreValue = new BigDecimal(redisearchResultModel.getScoreValue());
|
|
|
+ if (scoreValue.compareTo(BigDecimal.ZERO) == 0 || scoreValue.compareTo(new BigDecimal(redisearchConf.getScore())) > 0) {
|
|
|
+ String dataKey = redisearchResultModel.getDataKey();
|
|
|
+ dataKey = dataKey.replace(prefix, "");
|
|
|
+ String userId = dataKey.substring(0, 24);
|
|
|
+ return ResultContent.buildContent(userId);
|
|
|
+ }else {
|
|
|
+ return ResultContent.build(ResultState.FaceNoMatches);
|
|
|
+ }
|
|
|
+
|
|
|
+ }
|
|
|
+
|
|
|
+
|
|
|
+ private static RedisearchResultModel processQueryResult(Object result) {
|
|
|
+ RedisearchResultModel redisearchResultModel = new RedisearchResultModel();
|
|
|
+
|
|
|
+ if (result instanceof List){
|
|
|
+ List<Object> list = (List) result;
|
|
|
+ for (Object item : list) {
|
|
|
+ if (item instanceof byte[]) {// data key
|
|
|
+ byte[] bytes = ((byte[]) item);
|
|
|
+ System.out.println("Found vector: " + new String(bytes)); // 可以根据需要进一步处理
|
|
|
+ redisearchResultModel.setDataKey(new String(bytes));
|
|
|
+ } else if (item instanceof Long){// 返回的结果数
|
|
|
+ System.out.println("Found Long: " + item);
|
|
|
+ redisearchResultModel.setCount((Long)item);
|
|
|
+ }else if (item instanceof List) {// 对应的 距离
|
|
|
+ List<Object> itemList = (List) item;
|
|
|
+ for (Object item1 : itemList) {
|
|
|
+ if (item1 instanceof byte[]){
|
|
|
+ byte[] bytes = ((byte[]) item1);
|
|
|
+ System.out.println("Found vector: " + new String(bytes)); // 可以根据需要进一步处理
|
|
|
+ String str = new String(bytes);
|
|
|
+ if (str.equals("score")){
|
|
|
+ redisearchResultModel.setScoreKey(str);
|
|
|
+ }else {
|
|
|
+ redisearchResultModel.setScoreValue(str);
|
|
|
+ }
|
|
|
+ }
|
|
|
+ }
|
|
|
+ }
|
|
|
+ }
|
|
|
+ }
|
|
|
+ return redisearchResultModel;
|
|
|
}
|
|
|
|
|
|
/**
|
|
|
@@ -163,7 +421,7 @@ public class UserFaceServiceImpl implements UserFaceService {
|
|
|
* @throws IOException 如果发生 I/O 错误
|
|
|
*/
|
|
|
@SneakyThrows
|
|
|
- public static String convertInputStreamToBase64(InputStream inputStream){
|
|
|
+ public static String convertInputStreamToBase64(InputStream inputStream) {
|
|
|
@Cleanup ByteArrayOutputStream outputStream = new ByteArrayOutputStream();
|
|
|
byte[] buffer = new byte[1024];
|
|
|
int bytesRead;
|
|
|
@@ -175,7 +433,7 @@ public class UserFaceServiceImpl implements UserFaceService {
|
|
|
}
|
|
|
|
|
|
|
|
|
- private byte[] imageResizer(String base64Image){
|
|
|
+ private byte[] imageResizer(String base64Image) {
|
|
|
// 解码 Base64 字符串为 BufferedImage
|
|
|
BufferedImage originalImage = decodeBase64ToImage(base64Image);
|
|
|
|
|
|
@@ -187,6 +445,22 @@ public class UserFaceServiceImpl implements UserFaceService {
|
|
|
|
|
|
}
|
|
|
|
|
|
+// public static void resizeImage(InputStream inputStream, int width, int height) throws IOException {
|
|
|
+// BufferedImage inputImage = ImageIO.read(inputStream);
|
|
|
+//
|
|
|
+// // 创建一个输出的 BufferedImage
|
|
|
+// BufferedImage outputImage = new BufferedImage(width, height, inputImage.getType());
|
|
|
+//
|
|
|
+// // 使用 Graphics2D 绘制缩放后的图片
|
|
|
+// Graphics2D g2d = outputImage.createGraphics();
|
|
|
+// g2d.drawImage(inputImage, 0, 0, width, height, null);
|
|
|
+// g2d.dispose();
|
|
|
+//
|
|
|
+// // 输出到文件
|
|
|
+// String formatName = outputFile.getName().substring(outputFile.getName().lastIndexOf(".") + 1);
|
|
|
+// ImageIO.write(outputImage, formatName, outputFile);
|
|
|
+// }
|
|
|
+
|
|
|
private static BufferedImage resizeImage(BufferedImage originalImage, int width, int height) {
|
|
|
BufferedImage resizedImage = new BufferedImage(width, height, originalImage.getType());
|
|
|
Graphics2D g = resizedImage.createGraphics();
|
|
|
@@ -206,8 +480,8 @@ public class UserFaceServiceImpl implements UserFaceService {
|
|
|
|
|
|
@SneakyThrows
|
|
|
private static byte[] encodeImageToBytes(BufferedImage image) {
|
|
|
- @Cleanup ByteArrayOutputStream baos = new ByteArrayOutputStream();
|
|
|
- ImageIO.write(image, "png", baos);
|
|
|
- return baos.toByteArray();
|
|
|
+ @Cleanup ByteArrayOutputStream baos = new ByteArrayOutputStream();
|
|
|
+ ImageIO.write(image, "png", baos);
|
|
|
+ return baos.toByteArray();
|
|
|
}
|
|
|
}
|