mirror of
https://github.com/geekwenjie/SmartJavaAI.git
synced 2026-09-15 22:57:26 +00:00
1、OCR:新增表格识别模型
2、OCR:新增9个通用模型 3、OCR:支持批量检测识别 4、OCR:新增更多参数,使用更加灵活 5、人脸识别:支持ID查询及分页获取人脸信息 6、活体检测:视频检测支持设置最大帧数
This commit is contained in:
@@ -14,8 +14,11 @@ import io.milvus.param.*;
|
||||
import io.milvus.param.collection.*;
|
||||
import io.milvus.param.dml.*;
|
||||
import io.milvus.param.index.CreateIndexParam;
|
||||
import io.milvus.response.DescCollResponseWrapper;
|
||||
import io.milvus.response.QueryResultsWrapper;
|
||||
import io.milvus.response.SearchResultsWrapper;
|
||||
import io.milvus.v2.service.collection.request.DescribeCollectionReq;
|
||||
import io.milvus.v2.service.collection.response.DescribeCollectionResp;
|
||||
import lombok.extern.slf4j.Slf4j;
|
||||
import org.apache.commons.lang3.StringUtils;
|
||||
|
||||
@@ -53,6 +56,14 @@ public class MilvusClient implements VectorDBClient {
|
||||
serviceClient = new MilvusServiceClient(connectParam);
|
||||
collectionName = StringUtils.isNotBlank(config.getCollectionName()) ? config.getCollectionName() : VectorDBConstants.Defaults.DEFAULT_COLLECTION_NAME;
|
||||
createCollection(collectionName, config.getDimension());
|
||||
|
||||
boolean isAutoID = isAutoID(collectionName);
|
||||
if(isAutoID && config.getIdStrategy() != IdStrategy.AUTO){
|
||||
throw new VectorDBException("ID策略与当前Collection不匹配");
|
||||
}
|
||||
if(!isAutoID && config.getIdStrategy() == IdStrategy.AUTO){
|
||||
throw new VectorDBException("ID策略与当前Collection不匹配");
|
||||
}
|
||||
if(config.isUseMemoryCache()){
|
||||
// 加载集合到内存
|
||||
loadFaceFeatures();
|
||||
@@ -152,6 +163,21 @@ public class MilvusClient implements VectorDBClient {
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* 判断是否为自增长ID
|
||||
* @param collectionName
|
||||
* @return
|
||||
*/
|
||||
private boolean isAutoID(String collectionName) {
|
||||
R<DescribeCollectionResponse> response = serviceClient.describeCollection(
|
||||
DescribeCollectionParam.newBuilder()
|
||||
.withCollectionName(collectionName)
|
||||
.build()
|
||||
);
|
||||
DescCollResponseWrapper wrapper = new DescCollResponseWrapper(response.getData());
|
||||
return wrapper.getPrimaryField().isAutoID();
|
||||
}
|
||||
|
||||
@Override
|
||||
public void dropCollection(String collectionName) {
|
||||
try {
|
||||
@@ -204,6 +230,7 @@ public class MilvusClient implements VectorDBClient {
|
||||
if(faceVector.getVector() == null || faceVector.getVector().length == 0){
|
||||
throw new VectorDBException("插入数据失败:vector不能为空");
|
||||
}
|
||||
|
||||
//自定义ID
|
||||
if(config.getIdStrategy() == IdStrategy.CUSTOM){
|
||||
if(StringUtils.isBlank(faceVector.getId())){
|
||||
@@ -525,40 +552,22 @@ public class MilvusClient implements VectorDBClient {
|
||||
}
|
||||
}
|
||||
|
||||
public void releaseCollection(String collectionName) {
|
||||
if (!isInit){
|
||||
throw new VectorDBException("Milvus未初始化完毕");
|
||||
}
|
||||
R<RpcStatus> response = serviceClient.releaseCollection(ReleaseCollectionParam.newBuilder()
|
||||
.withCollectionName(collectionName)
|
||||
.build());
|
||||
|
||||
if (response.getStatus() != R.Status.Success.getCode()) {
|
||||
throw new VectorDBException("Milvus releaseCollection失败,msg: " + response.getMessage());
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@Override
|
||||
public FaceSearchResult getById(String id) {
|
||||
public FaceVector getFaceInfoById(String id) {
|
||||
try {
|
||||
if (!isInit){
|
||||
if (!isInit) {
|
||||
throw new VectorDBException("Milvus未初始化完毕");
|
||||
}
|
||||
// 构造搜索参数
|
||||
SearchParam searchParam = SearchParam.newBuilder()
|
||||
.withCollectionName(collectionName)
|
||||
.withExpr(VectorDBConstants.FieldNames.ID_FIELD + " == " + id)
|
||||
.withOutFields(Arrays.asList(VectorDBConstants.FieldNames.ID_FIELD, VectorDBConstants.FieldNames.METADATA_FIELD))
|
||||
.build();
|
||||
|
||||
|
||||
String expr = VectorDBConstants.FieldNames.ID_FIELD + " == '" + id + "'";
|
||||
if(config.getIdStrategy() == IdStrategy.AUTO){
|
||||
expr = VectorDBConstants.FieldNames.ID_FIELD + " == " + id;
|
||||
}
|
||||
// 5. 执行查询
|
||||
R<QueryResults> response = serviceClient.query(
|
||||
QueryParam.newBuilder()
|
||||
.withCollectionName(collectionName)
|
||||
.withExpr(VectorDBConstants.FieldNames.ID_FIELD + " == " + id)
|
||||
.withOutFields(Arrays.asList(VectorDBConstants.FieldNames.ID_FIELD, VectorDBConstants.FieldNames.METADATA_FIELD))
|
||||
.withExpr(expr)
|
||||
.withOutFields(Arrays.asList(VectorDBConstants.FieldNames.ID_FIELD, VectorDBConstants.FieldNames.VECTOR_FIELD, VectorDBConstants.FieldNames.METADATA_FIELD))
|
||||
.build()
|
||||
);
|
||||
|
||||
@@ -574,12 +583,91 @@ public class MilvusClient implements VectorDBClient {
|
||||
}
|
||||
// 提取第一条记录
|
||||
QueryResultsWrapper.RowRecord row = records.get(0);
|
||||
return new FaceSearchResult(id, 1,(String)row.get(VectorDBConstants.FieldNames.METADATA_FIELD));
|
||||
Object vectorObj = row.get(VectorDBConstants.FieldNames.VECTOR_FIELD);
|
||||
float[] vector = null;
|
||||
if (vectorObj instanceof List<?>) {
|
||||
// Milvus SDK通常返回List<Float>,转成float[]
|
||||
List<Float> vectorList = (List<Float>) vectorObj;
|
||||
vector = new float[vectorList.size()];
|
||||
for (int i = 0; i < vectorList.size(); i++) {
|
||||
vector[i] = vectorList.get(i);
|
||||
}
|
||||
}
|
||||
return new FaceVector(id, vector, (String) row.get(VectorDBConstants.FieldNames.METADATA_FIELD));
|
||||
} catch (Exception e) {
|
||||
throw new VectorDBException("搜索 Milvus 向量失败", e);
|
||||
throw new RuntimeException(e);
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public List<FaceVector> listFaces(long pageNum, long pageSize) {
|
||||
try {
|
||||
if (!isInit) {
|
||||
throw new VectorDBException("Milvus未初始化完毕");
|
||||
}
|
||||
if (pageNum < 1 || pageSize < 1) {
|
||||
throw new IllegalArgumentException("pageNum和pageSize必须大于0");
|
||||
}
|
||||
long offset = (pageNum - 1) * pageSize;
|
||||
// 构造查询参数,使用offset和limit实现分页
|
||||
QueryParam queryParam = QueryParam.newBuilder()
|
||||
.withCollectionName(collectionName)
|
||||
.withOutFields(Arrays.asList(
|
||||
VectorDBConstants.FieldNames.ID_FIELD,
|
||||
VectorDBConstants.FieldNames.VECTOR_FIELD,
|
||||
VectorDBConstants.FieldNames.METADATA_FIELD))
|
||||
.withOffset(offset)
|
||||
.withLimit(pageSize)
|
||||
.build();
|
||||
|
||||
R<QueryResults> response = serviceClient.query(queryParam);
|
||||
|
||||
if (response.getStatus() != R.Status.Success.getCode()) {
|
||||
throw new VectorDBException("分页查询失败: " + response.getMessage());
|
||||
}
|
||||
|
||||
QueryResultsWrapper wrapper = new QueryResultsWrapper(response.getData());
|
||||
List<QueryResultsWrapper.RowRecord> records = wrapper.getRowRecords();
|
||||
if (records.isEmpty()) {
|
||||
return Collections.emptyList();
|
||||
}
|
||||
|
||||
List<FaceVector> result = new ArrayList<>();
|
||||
for (QueryResultsWrapper.RowRecord row : records) {
|
||||
String id = (String) row.get(VectorDBConstants.FieldNames.ID_FIELD);
|
||||
Object vectorObj = row.get(VectorDBConstants.FieldNames.VECTOR_FIELD);
|
||||
float[] vector = null;
|
||||
if (vectorObj instanceof List<?>) {
|
||||
List<Float> vectorList = (List<Float>) vectorObj;
|
||||
vector = new float[vectorList.size()];
|
||||
for (int i = 0; i < vectorList.size(); i++) {
|
||||
vector[i] = vectorList.get(i);
|
||||
}
|
||||
}
|
||||
String metadata = (String) row.get(VectorDBConstants.FieldNames.METADATA_FIELD);
|
||||
result.add(new FaceVector(id, vector, metadata));
|
||||
}
|
||||
|
||||
return result;
|
||||
} catch (Exception e) {
|
||||
throw new RuntimeException(e);
|
||||
}
|
||||
}
|
||||
|
||||
public void releaseCollection(String collectionName) {
|
||||
if (!isInit){
|
||||
throw new VectorDBException("Milvus未初始化完毕");
|
||||
}
|
||||
R<RpcStatus> response = serviceClient.releaseCollection(ReleaseCollectionParam.newBuilder()
|
||||
.withCollectionName(collectionName)
|
||||
.build());
|
||||
|
||||
if (response.getStatus() != R.Status.Success.getCode()) {
|
||||
throw new VectorDBException("Milvus releaseCollection失败,msg: " + response.getMessage());
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@Override
|
||||
public void loadFaceFeatures() {
|
||||
// 加载集合到内存
|
||||
|
||||
@@ -196,6 +196,42 @@ public class SQLiteClient implements VectorDBClient {
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public FaceVector getFaceInfoById(String id) {
|
||||
if (!isInit) {
|
||||
throw new VectorDBException("人脸库未加载完毕");
|
||||
}
|
||||
// 先从内存缓存中获取
|
||||
FaceVector faceVector = memoryIndex.get(id);
|
||||
if (faceVector == null) {
|
||||
// 如果内存中没有,则从数据库查询
|
||||
try {
|
||||
faceVector = faceDao.findById(id);
|
||||
} catch (SQLException | ClassNotFoundException e) {
|
||||
throw new VectorDBException("SQLite查询异常", e);
|
||||
}
|
||||
}
|
||||
return faceVector;
|
||||
}
|
||||
|
||||
@Override
|
||||
public List<FaceVector> listFaces(long pageNum, long pageSize) {
|
||||
if (!isInit) {
|
||||
throw new VectorDBException("人脸库未加载完毕");
|
||||
}
|
||||
|
||||
if (pageNum < 1 || pageSize < 1) {
|
||||
throw new IllegalArgumentException("pageNum和pageSize必须大于0");
|
||||
}
|
||||
|
||||
// 从数据库中查询指定分页的数据
|
||||
try {
|
||||
return faceDao.findFace((int)pageNum, (int)pageSize);
|
||||
} catch (Exception e) {
|
||||
throw new VectorDBException("分页查询失败", e);
|
||||
}
|
||||
}
|
||||
|
||||
// ============= 私有辅助方法 =============
|
||||
|
||||
private void loadAllFeaturesToMemory() {
|
||||
@@ -234,19 +270,6 @@ public class SQLiteClient implements VectorDBClient {
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public FaceSearchResult getById(String id) {
|
||||
try {
|
||||
FaceVector faceVector = faceDao.findById(id);
|
||||
if(faceVector != null){
|
||||
return new FaceSearchResult(faceVector.getId(), 1.0f, faceVector.getMetadata());
|
||||
}
|
||||
return null;
|
||||
} catch (SQLException | RuntimeException | ClassNotFoundException e ) {
|
||||
throw new VectorDBException("SQLite查询异常", e);
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public void loadFaceFeatures() {
|
||||
// 加载所有特征到内存
|
||||
|
||||
@@ -1,5 +1,6 @@
|
||||
package cn.smartjavaai.face.vector.core;
|
||||
|
||||
import cn.smartjavaai.common.entity.R;
|
||||
import cn.smartjavaai.face.entity.FaceSearchParams;
|
||||
import cn.smartjavaai.face.vector.entity.FaceVector;
|
||||
import cn.smartjavaai.common.entity.face.FaceSearchResult;
|
||||
@@ -94,12 +95,21 @@ public interface VectorDBClient extends AutoCloseable {
|
||||
@Override
|
||||
void close();
|
||||
|
||||
|
||||
/**
|
||||
* 获取指定ID的向量
|
||||
* 使用人脸ID获取人脸信息
|
||||
* @param id
|
||||
* @return
|
||||
*/
|
||||
FaceSearchResult getById(String id);
|
||||
FaceVector getFaceInfoById(String id);
|
||||
|
||||
|
||||
/**
|
||||
* 获取人脸列表
|
||||
* @param pageNum
|
||||
* @param pageSize
|
||||
* @return
|
||||
*/
|
||||
List<FaceVector> listFaces(long pageNum, long pageSize);
|
||||
|
||||
/**
|
||||
* 加载人脸特征到内存
|
||||
|
||||
Reference in New Issue
Block a user